mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-27 03:32:55 +00:00
* fix(app): prevent web SVG prop and nested button warnings Consume Unistyles mapping props at the wrapper boundary and use web accessibility attributes for decorative rings. Register composer track rows as menu items so nested actions stay valid and keyboard selection remains available. * test(app): select archive actions by their menu role
133 lines
5.0 KiB
JavaScript
133 lines
5.0 KiB
JavaScript
import { copyFileSync, existsSync, mkdirSync, readdirSync, rmSync } from "node:fs";
|
|
import { spawnSync } from "node:child_process";
|
|
import { join, relative } from "node:path";
|
|
|
|
// In CI we often install a single workspace (e.g. server/relay/website). Only apply patches
|
|
// when the patched dependency is actually present.
|
|
// `cwd` is where patch-package must run from. Packages that npm does not hoist to the
|
|
// workspace root live in their workspace's own node_modules, and patch-package resolves
|
|
// the patch's node_modules/... paths relative to its working directory.
|
|
const patchedPackages = [
|
|
// Backport for expo-modules-core 57.0.23: https://github.com/expo/expo/pull/49634.
|
|
// Remove when the installed Expo SDK includes the Activity recreation fix.
|
|
{
|
|
nodeModulesPath: "node_modules/expo-modules-core",
|
|
patchPrefix: "expo-modules-core+",
|
|
},
|
|
{
|
|
nodeModulesPath: "packages/app/node_modules/react-native-enriched-markdown",
|
|
patchPrefix: "react-native-enriched-markdown+",
|
|
cwd: "packages/app",
|
|
},
|
|
// Registry cleanup: remove after react-native-unistyles ships
|
|
// https://github.com/jpudysz/react-native-unistyles/pull/1203.
|
|
// withUnistyles: also keep the uniProps filter until upstream consumes its control prop.
|
|
{
|
|
nodeModulesPath: "node_modules/react-native-unistyles",
|
|
patchPrefix: "react-native-unistyles+",
|
|
},
|
|
// Backport of https://github.com/software-mansion/react-native-reanimated/pull/10435
|
|
// (Reanimated 4.7.1): skip synchronous Android prop updates for unmounted view tags
|
|
// instead of throwing and printing a full stack trace on the UI thread per tag per event.
|
|
// Remove when the installed Reanimated is >= 4.7.1.
|
|
{
|
|
nodeModulesPath: "node_modules/react-native-reanimated",
|
|
patchPrefix: "react-native-reanimated+",
|
|
},
|
|
{
|
|
nodeModulesPath: "node_modules/react-native-draggable-flatlist",
|
|
patchPrefix: "react-native-draggable-flatlist+",
|
|
},
|
|
{
|
|
nodeModulesPath: "node_modules/react-native-gesture-handler",
|
|
patchPrefix: "react-native-gesture-handler+",
|
|
},
|
|
// Exports BottomSheetModalInternalProvider so a subtree can host its own sheets on the shared
|
|
// modal stack (see packages/app/src/components/ui/isolated-bottom-sheet-modal/host-scope.tsx), and
|
|
// keeps a dismissing modal's status through its final onChange(-1), so a modal with
|
|
// enableDismissOnClose=false that unmounts while presented still leaves the portal.
|
|
{
|
|
nodeModulesPath: "node_modules/@gorhom/bottom-sheet",
|
|
patchPrefix: "@gorhom+bottom-sheet+",
|
|
},
|
|
{
|
|
nodeModulesPath: "packages/app/node_modules/react-native-svg",
|
|
patchPrefix: "react-native-svg+",
|
|
cwd: "packages/app",
|
|
},
|
|
{
|
|
nodeModulesPath: "node_modules/@mattermost/react-native-paste-input",
|
|
patchPrefix: "@mattermost+react-native-paste-input+",
|
|
},
|
|
{
|
|
nodeModulesPath: "packages/server/node_modules/@opencode-ai/sdk",
|
|
patchPrefix: "@opencode-ai+sdk+",
|
|
cwd: "packages/server",
|
|
},
|
|
];
|
|
|
|
const installedPackages = patchedPackages.filter(({ nodeModulesPath }) =>
|
|
existsSync(nodeModulesPath),
|
|
);
|
|
|
|
if (!existsSync("patches") || installedPackages.length === 0) {
|
|
process.exit(0);
|
|
}
|
|
|
|
const patchFiles = readdirSync("patches").filter((file) => file.endsWith(".patch"));
|
|
|
|
const isWindows = process.platform === "win32";
|
|
const cmd = isWindows ? "patch-package.cmd" : "patch-package";
|
|
|
|
let failed = false;
|
|
for (const [index, { nodeModulesPath, patchPrefix, cwd = "." }] of installedPackages.entries()) {
|
|
const files = patchFiles.filter((file) => file.startsWith(patchPrefix));
|
|
if (files.length === 0) {
|
|
continue;
|
|
}
|
|
const outcome = applyPatches(cwd, files, index);
|
|
if (outcome === "applied") {
|
|
continue;
|
|
}
|
|
failed = true;
|
|
if (outcome === "unavailable") {
|
|
continue;
|
|
}
|
|
// patch-package cannot apply a patch that changed after an earlier version of it was
|
|
// applied. Without the package, the next install fetches it clean and applies the patch.
|
|
rmSync(nodeModulesPath, { recursive: true, force: true });
|
|
console.error(
|
|
`postinstall-patches: removed ${nodeModulesPath} because its patch did not apply. ` +
|
|
"Run npm install again to reinstall it with the current patch. " +
|
|
"If it fails again on the clean package, the patch is out of date and must be regenerated.",
|
|
);
|
|
}
|
|
|
|
process.exit(failed ? 1 : 0);
|
|
|
|
function applyPatches(cwd, files, index) {
|
|
const tempPatchDir = join(".tmp", `postinstall-patches-${process.pid}-${index}`);
|
|
mkdirSync(tempPatchDir, { recursive: true });
|
|
for (const patchFile of files) {
|
|
copyFileSync(join("patches", patchFile), join(tempPatchDir, patchFile));
|
|
}
|
|
|
|
let result;
|
|
try {
|
|
result = spawnSync(cmd, ["--patch-dir", relative(cwd, tempPatchDir), "--error-on-fail"], {
|
|
cwd,
|
|
shell: isWindows,
|
|
stdio: "inherit",
|
|
windowsHide: true,
|
|
});
|
|
} finally {
|
|
rmSync(tempPatchDir, { recursive: true, force: true });
|
|
}
|
|
|
|
if (result.error) {
|
|
console.error("postinstall-patches: patch-package failed to spawn:", result.error.message);
|
|
return "unavailable";
|
|
}
|
|
return result.status === 0 ? "applied" : "rejected";
|
|
}
|