mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-22 17:22:47 +00:00
* fix(scripts): recover installs when a dependency patch changed patch-package cannot apply a patch over a package patched with an earlier version of it, and without --error-on-fail it exits 0 locally. Checkouts kept the stale patch silently: the Markdown code block spacing fix never reached them. The script now fails the install and removes that package so the next npm install reinstalls it clean with the current patch. A patch-package that cannot start fails the install without removing anything. * fix(app): give Markdown blocks one gap and roomier desktop spacing Every Markdown block is followed by one gap, density.blockGap: 12 on compact layouts and 16 wider. The library's element styles and the views stacked outside it (Mermaid segments on native, streaming head and tail) take the same token, so no block type carries its own margins. Desktop was too tight at 12. Markdown images show a zoom-in cursor on web, since tapping opens the lightbox.
117 lines
4.2 KiB
JavaScript
117 lines
4.2 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 = [
|
|
{
|
|
nodeModulesPath: "packages/app/node_modules/react-native-enriched-markdown",
|
|
patchPrefix: "react-native-enriched-markdown+",
|
|
cwd: "packages/app",
|
|
},
|
|
// Remove after react-native-unistyles ships
|
|
// https://github.com/jpudysz/react-native-unistyles/pull/1203.
|
|
{
|
|
nodeModulesPath: "node_modules/react-native-unistyles",
|
|
patchPrefix: "react-native-unistyles+",
|
|
},
|
|
{
|
|
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: "node_modules/react-native-svg",
|
|
patchPrefix: "react-native-svg+",
|
|
},
|
|
{
|
|
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";
|
|
}
|