pob 40.3.1 → 40.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,8 +7,11 @@ import * as packageUtils from "../../utils/package.js";
7
7
  import { packageManagerRun } from "../../utils/packageManagerUtils.js";
8
8
  import {
9
9
  workspacesRun,
10
+ workspacesRunExcluding,
11
+ workspacesRunOnly,
10
12
  workspacesRunSequential,
11
13
  } from "../../utils/packageManagerWorkspacesUtils.js";
14
+ import { getRollupConfigDependencies } from "../../utils/rollupConfigDependencies.js";
12
15
  import {
13
16
  detectStorybook,
14
17
  detectStorybookReactNative,
@@ -453,6 +456,7 @@ export default class PobMonorepoGenerator extends Generator {
453
456
  });
454
457
 
455
458
  const rollupConfigs = [];
459
+ const rollupConfigContents = [];
456
460
  this.packageLocations.forEach((location) => {
457
461
  const rollupPath = `${location}/rollup.config.mjs`;
458
462
  const rollupConfig = this.fs.read(this.destinationPath(rollupPath), {
@@ -460,9 +464,21 @@ export default class PobMonorepoGenerator extends Generator {
460
464
  });
461
465
  if (rollupConfig) {
462
466
  rollupConfigs.push(rollupPath);
467
+ rollupConfigContents.push(rollupConfig);
463
468
  }
464
469
  });
465
470
 
471
+ // built before the root rollup config loads them, and kept out of
472
+ // clean:build which runs in between
473
+ const rollupConfigDependencies = getRollupConfigDependencies(
474
+ this.packages,
475
+ rollupConfigContents,
476
+ );
477
+ const buildRollupConfigDependencies =
478
+ rollupConfigDependencies.length > 0
479
+ ? `${workspacesRunOnly(this.options.packageManager, "build", ...rollupConfigDependencies)} && `
480
+ : "";
481
+
466
482
  if (rollupConfigs.length > 0) {
467
483
  await copyAndFormatTpl(
468
484
  this.fs,
@@ -476,12 +492,16 @@ export default class PobMonorepoGenerator extends Generator {
476
492
  this.fs.delete("rollup.config.mjs");
477
493
  }
478
494
  packageUtils.addOrRemoveScripts(pkg, rollupConfigs.length > 0, {
479
- "clean:build": workspacesRun(
480
- this.options.packageManager,
481
- "clean:build",
482
- ),
483
- build: `${packageManagerRun(this.options.packageManager, "clean:build")} && rollup --config rollup.config.mjs`,
484
- watch: `${packageManagerRun(this.options.packageManager, "clean:build")} && rollup --config rollup.config.mjs --watch`,
495
+ "clean:build":
496
+ rollupConfigDependencies.length > 0
497
+ ? workspacesRunExcluding(
498
+ this.options.packageManager,
499
+ "clean:build",
500
+ ...rollupConfigDependencies,
501
+ )
502
+ : workspacesRun(this.options.packageManager, "clean:build"),
503
+ build: `${buildRollupConfigDependencies}${packageManagerRun(this.options.packageManager, "clean:build")} && rollup --config rollup.config.mjs`,
504
+ watch: `${buildRollupConfigDependencies}${packageManagerRun(this.options.packageManager, "clean:build")} && rollup --config rollup.config.mjs --watch`,
485
505
  });
486
506
 
487
507
  const hasExpoApp = this.packageConfigs.some(
@@ -58,6 +58,42 @@ export const workspacesRunSequential = (packageManager, script) => {
58
58
  }
59
59
  };
60
60
 
61
+ /**
62
+ * Run a script in the given workspaces only, in topological dependency order.
63
+ * Use to build packages other builds depend on first.
64
+ */
65
+ export const workspacesRunOnly = (packageManager, script, ...packageNames) => {
66
+ switch (packageManager) {
67
+ case undefined:
68
+ case "yarn": {
69
+ const includeArgs = packageNames
70
+ .map((name) => `--include "${name}"`)
71
+ .join(" ");
72
+ return `yarn workspaces foreach --topological-dev ${includeArgs} -Av run ${script}`;
73
+ }
74
+ case "pnpm": {
75
+ const filterArgs = packageNames
76
+ .map((name) => `--filter "${name}"`)
77
+ .join(" ");
78
+ return `pnpm ${filterArgs} run ${script}`;
79
+ }
80
+ case "npm": {
81
+ const workspaceArgs = packageNames
82
+ .map((name) => `--workspace "${name}"`)
83
+ .join(" ");
84
+ return `npm run ${script} ${workspaceArgs}`;
85
+ }
86
+ case "bun": {
87
+ const filterArgs = packageNames
88
+ .map((name) => `--filter '${name}'`)
89
+ .join(" ");
90
+ return `bun ${filterArgs} run ${script}`;
91
+ }
92
+ default:
93
+ throw new Error(`Unsupported package manager: ${packageManager}`);
94
+ }
95
+ };
96
+
61
97
  /**
62
98
  * Run a script in all workspaces in parallel, excluding packages matching the given patterns.
63
99
  * Use for watch commands where example/demo packages should be skipped.
@@ -0,0 +1,17 @@
1
+ const escapeRegExp = (value) => value.replaceAll(/[$()*+.?[\\\]^{|}]/g, "\\$&");
2
+
3
+ /**
4
+ * Names of the workspace packages imported by a rollup config (e.g. a rollup
5
+ * plugin): the root rollup config loads them from their build output, so
6
+ * they must be built before it runs. Only packages with a build script.
7
+ */
8
+ export const getRollupConfigDependencies = (packages, rollupConfigContents) =>
9
+ packages
10
+ .filter((pkg) => {
11
+ if (!pkg.scripts?.build) return false;
12
+ const importRegex = new RegExp(
13
+ `from\\s+["']${escapeRegExp(pkg.name)}(?:/[^"']*)?["']`,
14
+ );
15
+ return rollupConfigContents.some((content) => importRegex.test(content));
16
+ })
17
+ .map((pkg) => pkg.name);
@@ -0,0 +1,48 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { getRollupConfigDependencies } from "./rollupConfigDependencies.js";
3
+
4
+ const plugin = {
5
+ name: "alp-rollup-plugin-config",
6
+ scripts: { build: "rollup --config rollup.config.mjs" },
7
+ };
8
+ const lib = { name: "alp-node", scripts: { build: "rollup" } };
9
+
10
+ const appConfig = `import createRollupConfig from "@pob/rollup-esbuild/createRollupConfig.js";
11
+ import config from "alp-rollup-plugin-config";
12
+ `;
13
+
14
+ describe("getRollupConfigDependencies", () => {
15
+ it("returns workspace packages imported by a rollup config", () => {
16
+ expect(getRollupConfigDependencies([lib, plugin], [appConfig])).toEqual([
17
+ "alp-rollup-plugin-config",
18
+ ]);
19
+ });
20
+
21
+ it("detects single quotes and subpath imports", () => {
22
+ expect(
23
+ getRollupConfigDependencies(
24
+ [plugin],
25
+ ["import config from 'alp-rollup-plugin-config/plugin.js';"],
26
+ ),
27
+ ).toEqual(["alp-rollup-plugin-config"]);
28
+ });
29
+
30
+ it("ignores packages whose name is only a prefix of the import", () => {
31
+ expect(
32
+ getRollupConfigDependencies(
33
+ [{ name: "alp", scripts: { build: "rollup" } }],
34
+ [appConfig],
35
+ ),
36
+ ).toEqual([]);
37
+ });
38
+
39
+ it("ignores packages without build script", () => {
40
+ expect(
41
+ getRollupConfigDependencies([{ name: plugin.name }], [appConfig]),
42
+ ).toEqual([]);
43
+ });
44
+
45
+ it("returns nothing without rollup configs", () => {
46
+ expect(getRollupConfigDependencies([plugin], [])).toEqual([]);
47
+ });
48
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pob",
3
- "version": "40.3.1",
3
+ "version": "40.3.3",
4
4
  "description": "Pile of bones, library generator with git/babel/typescript/typedoc/readme/vitest",
5
5
  "keywords": [
6
6
  "skeleton"
@@ -31,7 +31,7 @@
31
31
  "./package.json": "./package.json"
32
32
  },
33
33
  "dependencies": {
34
- "@pob/codemods": "0.18.1",
34
+ "@pob/codemods": "0.18.2",
35
35
  "@pob/eslint-config": "68.0.0",
36
36
  "@pob/eslint-config-typescript-react": "68.0.0",
37
37
  "@pob/sort-object": "11.2.0",
@@ -59,7 +59,7 @@
59
59
  "yeoman-generator": "10.3.0"
60
60
  },
61
61
  "devDependencies": {
62
- "@pob/root": "28.2.1",
62
+ "@pob/root": "28.2.2",
63
63
  "@types/node": "24.19.1",
64
64
  "@typescript/native": "npm:typescript@7.0.2",
65
65
  "@yeoman/types": "1.13.1",