pob 40.1.0 → 40.3.0
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.
- package/lib/generators/app/PobAppGenerator.js +11 -2
- package/lib/generators/common/format-lint/CommonLintGenerator.js +23 -1
- package/lib/generators/common/transpiler/CommonTranspilerGenerator.js +8 -6
- package/lib/generators/common/typescript/CommonTypescriptGenerator.js +11 -6
- package/lib/generators/core/gitignore/CoreGitignoreGenerator.js +2 -0
- package/lib/generators/core/gitignore/templates/gitignore.ejs +6 -0
- package/lib/generators/core/vscode/CoreVSCodeGenerator.js +19 -0
- package/lib/generators/core/vscode/templates/settings.json.ejs +10 -0
- package/lib/generators/core/vscode/templates/tsrs-tsdk-tsgo +9 -0
- package/lib/generators/lib/PobLibGenerator.js +0 -1
- package/lib/generators/monorepo/PobMonorepoGenerator.js +30 -2
- package/lib/generators/monorepo/typescript/MonorepoTypescriptGenerator.js +25 -6
- package/lib/generators/monorepo/workspaces/MonorepoWorkspacesGenerator.js +5 -1
- package/lib/utils/designSync.js +12 -0
- package/lib/utils/nodeEngines.js +32 -13
- package/lib/utils/nodeEngines.test.js +28 -3
- package/lib/utils/storybook.js +26 -0
- package/package.json +11 -9
|
@@ -5,6 +5,7 @@ import { removeFromGitIndex } from "../../utils/git.js";
|
|
|
5
5
|
import inMonorepo from "../../utils/inMonorepo.js";
|
|
6
6
|
import removeLegacyGeneratedDocs from "../../utils/legacyGeneratedDocs.js";
|
|
7
7
|
import * as packageUtils from "../../utils/package.js";
|
|
8
|
+
import { detectStorybookReactNative } from "../../utils/storybook.js";
|
|
8
9
|
import { appIgnorePaths } from "./ignorePaths.js";
|
|
9
10
|
|
|
10
11
|
const appsWithTypescript = [
|
|
@@ -95,6 +96,13 @@ export default class PobAppGenerator extends Generator {
|
|
|
95
96
|
delete config.ci;
|
|
96
97
|
}
|
|
97
98
|
|
|
99
|
+
const storybookDefault = detectStorybookReactNative([
|
|
100
|
+
this.fs.readJSON(this.destinationPath("package.json"), {}),
|
|
101
|
+
]);
|
|
102
|
+
if (config?.type === "expo" && config.storybook === undefined) {
|
|
103
|
+
config.storybook = storybookDefault;
|
|
104
|
+
}
|
|
105
|
+
|
|
98
106
|
if (config && this.options.updateOnly) {
|
|
99
107
|
this.config.set("app", this.appConfig);
|
|
100
108
|
this.config.save();
|
|
@@ -151,7 +159,7 @@ export default class PobAppGenerator extends Generator {
|
|
|
151
159
|
type: "confirm",
|
|
152
160
|
name: "storybook",
|
|
153
161
|
message: "Do you want storybook ?",
|
|
154
|
-
default:
|
|
162
|
+
default: config?.storybook ?? storybookDefault,
|
|
155
163
|
when: (values) => values.type === "expo",
|
|
156
164
|
},
|
|
157
165
|
]);
|
|
@@ -315,7 +323,8 @@ export default class PobAppGenerator extends Generator {
|
|
|
315
323
|
this.composeWith("pob:common:format-lint", {
|
|
316
324
|
isApp: true,
|
|
317
325
|
documentation: false,
|
|
318
|
-
|
|
326
|
+
// only asked for expo apps: the on-device react-native storybook
|
|
327
|
+
storybookReactNative: this.appConfig.storybook,
|
|
319
328
|
testing: this.appConfig.testing,
|
|
320
329
|
testRunner: this.appConfig.testRunner,
|
|
321
330
|
babel,
|
|
@@ -5,6 +5,7 @@ import { runTransform } from "@pob/codemods";
|
|
|
5
5
|
import { format } from "oxfmt";
|
|
6
6
|
import semver from "semver";
|
|
7
7
|
import Generator from "yeoman-generator";
|
|
8
|
+
import hasDesignSync from "../../../utils/designSync.js";
|
|
8
9
|
import { quoteArg } from "../../../utils/execUtils.js";
|
|
9
10
|
import inMonorepo from "../../../utils/inMonorepo.js";
|
|
10
11
|
import * as packageUtils from "../../../utils/package.js";
|
|
@@ -160,6 +161,13 @@ export default class CommonFormatLintGenerator extends Generator {
|
|
|
160
161
|
description: "Enable storybook",
|
|
161
162
|
});
|
|
162
163
|
|
|
164
|
+
this.option("storybookReactNative", {
|
|
165
|
+
type: Boolean,
|
|
166
|
+
required: false,
|
|
167
|
+
default: false,
|
|
168
|
+
description: "Enable the on-device react-native storybook",
|
|
169
|
+
});
|
|
170
|
+
|
|
163
171
|
this.option("rootAsSrc", {
|
|
164
172
|
type: Boolean,
|
|
165
173
|
required: false,
|
|
@@ -566,6 +574,20 @@ export default class CommonFormatLintGenerator extends Generator {
|
|
|
566
574
|
ignorePatterns.add("/rollup.config.mjs");
|
|
567
575
|
}
|
|
568
576
|
|
|
577
|
+
if (this.options.storybook) {
|
|
578
|
+
ignorePatterns.add("**/.storybook/");
|
|
579
|
+
ignorePatterns.add("**/storybook-static/");
|
|
580
|
+
}
|
|
581
|
+
if (this.options.storybookReactNative) {
|
|
582
|
+
ignorePatterns.add("**/.rnstorybook/");
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if (hasDesignSync(this)) {
|
|
586
|
+
ignorePatterns.add("/.design-sync/");
|
|
587
|
+
ignorePatterns.add("/.ds-sync/");
|
|
588
|
+
ignorePatterns.add("/ds-bundle/");
|
|
589
|
+
}
|
|
590
|
+
|
|
569
591
|
if (rootIgnorePaths) {
|
|
570
592
|
rootIgnorePaths.forEach((ignorePath) => {
|
|
571
593
|
if (ignorePath.startsWith("#")) return;
|
|
@@ -703,7 +725,7 @@ export default class CommonFormatLintGenerator extends Generator {
|
|
|
703
725
|
? `${packageManagerExecWithCwd(this.options.packageManager, "../..", "oxlint")} ${args} ${quoteArg(path.relative("../..", "."))}`
|
|
704
726
|
: `oxlint ${args}`,
|
|
705
727
|
lint: `${packageManagerRun(this.options.packageManager, "lint:oxlint")} && ${
|
|
706
|
-
useTypescript && !composite ? "
|
|
728
|
+
useTypescript && !composite ? "tsrs && " : ""
|
|
707
729
|
}${packageManagerRun(this.options.packageManager, "lint:eslint")}`,
|
|
708
730
|
});
|
|
709
731
|
|
|
@@ -178,7 +178,7 @@ export default class CommonTranspilerGenerator extends Generator {
|
|
|
178
178
|
if (bundler && bundler.startsWith("rollup")) {
|
|
179
179
|
return `${packageManagerRun(this.options.packageManager, "clean:build")} && rollup --config rollup.config.mjs --watch`;
|
|
180
180
|
}
|
|
181
|
-
if (bundler === "tsc") return "
|
|
181
|
+
if (bundler === "tsc") return "tsrs --watch";
|
|
182
182
|
if (bundler === "esbuild") return "pob-esbuild-watch";
|
|
183
183
|
})(),
|
|
184
184
|
});
|
|
@@ -194,7 +194,7 @@ export default class CommonTranspilerGenerator extends Generator {
|
|
|
194
194
|
if (bundler && bundler.startsWith("rollup")) {
|
|
195
195
|
return `${packageManagerRun(this.options.packageManager, "clean:build")} && rollup --config rollup.config.mjs`;
|
|
196
196
|
}
|
|
197
|
-
if (bundler === "tsc") return "
|
|
197
|
+
if (bundler === "tsc") return "tsrs";
|
|
198
198
|
if (bundler === "esbuild") return "pob-esbuild-build";
|
|
199
199
|
})(),
|
|
200
200
|
});
|
|
@@ -203,7 +203,7 @@ export default class CommonTranspilerGenerator extends Generator {
|
|
|
203
203
|
!this.options.isApp && withTypescript && bundler !== "tsc";
|
|
204
204
|
|
|
205
205
|
packageUtils.addOrRemoveScripts(pkg, shouldBuildDefinitions, {
|
|
206
|
-
"build:definitions": "
|
|
206
|
+
"build:definitions": "tsrs -p tsconfig.json",
|
|
207
207
|
});
|
|
208
208
|
|
|
209
209
|
if (shouldBuildDefinitions) {
|
|
@@ -218,7 +218,7 @@ export default class CommonTranspilerGenerator extends Generator {
|
|
|
218
218
|
if (this.fs.exists(this.destinationPath("lib/index.d.ts"))) {
|
|
219
219
|
packageUtils.addScripts(pkg, {
|
|
220
220
|
"build:definitions":
|
|
221
|
-
"
|
|
221
|
+
"tsrs --lib esnext --noEmit --skipLibCheck ./lib/index.d.ts",
|
|
222
222
|
build: packageManagerRun(
|
|
223
223
|
this.options.packageManager,
|
|
224
224
|
"build:definitions",
|
|
@@ -229,7 +229,7 @@ export default class CommonTranspilerGenerator extends Generator {
|
|
|
229
229
|
if (this.fs.exists(this.destinationPath("lib/index.ts"))) {
|
|
230
230
|
packageUtils.addScripts(pkg, {
|
|
231
231
|
"build:definitions":
|
|
232
|
-
"
|
|
232
|
+
"tsrs --lib esnext --noEmit --skipLibCheck ./lib/index.ts",
|
|
233
233
|
build: packageManagerRun(
|
|
234
234
|
this.options.packageManager,
|
|
235
235
|
"build:definitions",
|
|
@@ -740,7 +740,9 @@ export default class CommonTranspilerGenerator extends Generator {
|
|
|
740
740
|
}
|
|
741
741
|
|
|
742
742
|
end() {
|
|
743
|
-
|
|
743
|
+
// when updated from the monorepo root, dependencies are not installed yet:
|
|
744
|
+
// the root builds after installing
|
|
745
|
+
if (this.bundler && !this.options.fromPob) {
|
|
744
746
|
this.spawnCommandSync(
|
|
745
747
|
packageManagerRun(this.options.packageManager, "build"),
|
|
746
748
|
);
|
|
@@ -222,12 +222,13 @@ export default class CommonTypescriptGenerator extends Generator {
|
|
|
222
222
|
|
|
223
223
|
// "typescript" is aliased to the typescript 6 api package, still required by
|
|
224
224
|
// typescript-eslint and typedoc. "@typescript/native" is typescript 7, which
|
|
225
|
-
// provides the "tsc" binary.
|
|
225
|
+
// provides the "tsc" binary, kept for the "tsc:go" script. "tsrs" is the
|
|
226
|
+
// rust port of typescript 7, used by all the other scripts.
|
|
226
227
|
packageUtils.addOrRemoveDevDependencies(
|
|
227
228
|
pkg,
|
|
228
229
|
this.options.enable ||
|
|
229
230
|
this.fs.exists(this.destinationPath("lib/index.d.ts")),
|
|
230
|
-
["typescript", "@typescript/native"],
|
|
231
|
+
["typescript", "@typescript/native", "tsrs"],
|
|
231
232
|
);
|
|
232
233
|
|
|
233
234
|
const tsconfigPath = this.destinationPath("tsconfig.json");
|
|
@@ -401,11 +402,15 @@ export default class CommonTypescriptGenerator extends Generator {
|
|
|
401
402
|
}
|
|
402
403
|
|
|
403
404
|
if (!pkg.workspaces || !this.options.enable) {
|
|
405
|
+
// tsrs and tsc do not share their .tsbuildinfo: switching between them
|
|
406
|
+
// triggers a full rebuild
|
|
407
|
+
const tscCommand = (compiler) =>
|
|
408
|
+
inMonorepo || !this.options.enable
|
|
409
|
+
? compiler
|
|
410
|
+
: `${compiler} && ${compiler} -p tsconfig.tools.json`;
|
|
404
411
|
packageUtils.addOrRemoveScripts(pkg, this.options.enable, {
|
|
405
|
-
tsc:
|
|
406
|
-
|
|
407
|
-
? "tsc"
|
|
408
|
-
: "tsc && tsc -p tsconfig.tools.json",
|
|
412
|
+
tsc: tscCommand("tsrs"),
|
|
413
|
+
"tsc:go": tscCommand("tsc"),
|
|
409
414
|
});
|
|
410
415
|
}
|
|
411
416
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Generator from "yeoman-generator";
|
|
2
|
+
import hasDesignSync from "../../../utils/designSync.js";
|
|
2
3
|
|
|
3
4
|
export default class CoreGitignoreGenerator extends Generator {
|
|
4
5
|
constructor(args, opts) {
|
|
@@ -82,6 +83,7 @@ export default class CoreGitignoreGenerator extends Generator {
|
|
|
82
83
|
typescript: withBabel || this.options.typescript,
|
|
83
84
|
paths: this.options.paths,
|
|
84
85
|
playwright: this.options.playwright,
|
|
86
|
+
designSync: hasDesignSync(this),
|
|
85
87
|
});
|
|
86
88
|
}
|
|
87
89
|
|
|
@@ -69,6 +69,24 @@ export default class CoreVSCodeGenerator extends Generator {
|
|
|
69
69
|
async writing() {
|
|
70
70
|
if (this.options.root) {
|
|
71
71
|
const pkg = this.fs.readJSON(this.destinationPath("package.json"));
|
|
72
|
+
// the tsdk script runs tsrs from node_modules, which pnp does not have
|
|
73
|
+
const withTsrs =
|
|
74
|
+
this.options.typescript && this.options.yarnNodeLinker !== "pnp";
|
|
75
|
+
const tsdkPath = this.destinationPath(".vscode/tsrs-tsdk/tsgo");
|
|
76
|
+
|
|
77
|
+
if (withTsrs) {
|
|
78
|
+
// the extension runs it directly, so it must be executable
|
|
79
|
+
this.fs.write(
|
|
80
|
+
tsdkPath,
|
|
81
|
+
this.fs.read(this.templatePath("tsrs-tsdk-tsgo")),
|
|
82
|
+
{
|
|
83
|
+
stat: /** @type {import("node:fs").Stats} */ ({ mode: 0o755 }),
|
|
84
|
+
},
|
|
85
|
+
);
|
|
86
|
+
} else {
|
|
87
|
+
this.fs.delete(tsdkPath);
|
|
88
|
+
}
|
|
89
|
+
|
|
72
90
|
await copyAndFormatTpl(
|
|
73
91
|
this.fs,
|
|
74
92
|
this.templatePath("extensions.json.ejs"),
|
|
@@ -90,6 +108,7 @@ export default class CoreVSCodeGenerator extends Generator {
|
|
|
90
108
|
bun: this.options.packageManager === "bun",
|
|
91
109
|
pnpm: this.options.packageManager === "pnpm",
|
|
92
110
|
typescript: this.options.typescript,
|
|
111
|
+
tsrs: withTsrs,
|
|
93
112
|
testing: this.options.testing,
|
|
94
113
|
testRunner: this.options.testRunner,
|
|
95
114
|
module: pkg.type === "module",
|
|
@@ -17,6 +17,16 @@
|
|
|
17
17
|
// typescript 7 is provided by the TypeScriptTeam.native-preview extension.
|
|
18
18
|
// "typescript" resolves to the typescript 6 api package, which has no
|
|
19
19
|
// tsserver, so it cannot be used as "typescript.tsdk".
|
|
20
|
+
<% if (tsrs) { -%>
|
|
21
|
+
// The extension runs tsrs, the same compiler as the "tsc" script, through
|
|
22
|
+
// .vscode/tsrs-tsdk/tsgo once its "TypeScript 7 tsdk" prompt is allowed.
|
|
23
|
+
// Without the prompt, use "Select TypeScript Version…", which offers the
|
|
24
|
+
// "additionalLocations" entry.
|
|
25
|
+
"js/ts.experimental.useTsgo": true,
|
|
26
|
+
"js/ts.tsdk.path": ".vscode/tsrs-tsdk",
|
|
27
|
+
"js/ts.tsdk.additionalLocations": [".vscode/tsrs-tsdk"],
|
|
28
|
+
"js/ts.enablePromptUseWorkspaceTsdk": true,
|
|
29
|
+
<% } -%>
|
|
20
30
|
<% } -%>
|
|
21
31
|
|
|
22
32
|
<% if (yarn) { -%>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Generated by pob: do not edit, it is overwritten on each pob run.
|
|
3
|
+
# "js/ts.tsdk.path" points to this directory, so that the TypeScript 7
|
|
4
|
+
# extension (TypeScriptTeam.native-preview) runs the project's tsrs instead of
|
|
5
|
+
# its bundled typescript 7. The extension silently falls back to the bundled
|
|
6
|
+
# one when this fails: tsrs not installed, no tsrs binary for the platform
|
|
7
|
+
# (Windows, Intel macOS) or node not in VS Code's PATH.
|
|
8
|
+
# Check with: ps -axo command | grep -- '--lsp --stdio'
|
|
9
|
+
exec node "$(dirname "$0")/../../node_modules/tsrs/bin/tsrs" "$@"
|
|
@@ -365,7 +365,6 @@ export default class PobLibGenerator extends Generator {
|
|
|
365
365
|
documentation:
|
|
366
366
|
!!this.pobjson.documentation ||
|
|
367
367
|
!!(this.pobjson.testing && this.pobjson.testing.codecov),
|
|
368
|
-
storybook: pkg?.devDependencies?.storybook,
|
|
369
368
|
testing: !!this.pobjson.testing,
|
|
370
369
|
testRunner: inMonorepo
|
|
371
370
|
? inMonorepo.pobMonorepoConfig.testRunner
|
|
@@ -9,6 +9,10 @@ import {
|
|
|
9
9
|
workspacesRun,
|
|
10
10
|
workspacesRunSequential,
|
|
11
11
|
} from "../../utils/packageManagerWorkspacesUtils.js";
|
|
12
|
+
import {
|
|
13
|
+
detectStorybook,
|
|
14
|
+
detectStorybookReactNative,
|
|
15
|
+
} from "../../utils/storybook.js";
|
|
12
16
|
import {
|
|
13
17
|
buildDependenciesMaps,
|
|
14
18
|
buildTopologicalOrderBatches,
|
|
@@ -152,7 +156,16 @@ export default class PobMonorepoGenerator extends Generator {
|
|
|
152
156
|
}
|
|
153
157
|
|
|
154
158
|
async prompting() {
|
|
155
|
-
const
|
|
159
|
+
const storedConfig = this.config.get("monorepo");
|
|
160
|
+
const allPackages = [
|
|
161
|
+
this.fs.readJSON(this.destinationPath("package.json"), {}),
|
|
162
|
+
...this.packages,
|
|
163
|
+
];
|
|
164
|
+
const config = storedConfig && {
|
|
165
|
+
storybook: detectStorybook(allPackages),
|
|
166
|
+
storybookReactNative: detectStorybookReactNative(allPackages),
|
|
167
|
+
...storedConfig,
|
|
168
|
+
};
|
|
156
169
|
|
|
157
170
|
if (this.options.updateOnly && config) {
|
|
158
171
|
this.pobMonorepoConfig = config;
|
|
@@ -232,6 +245,20 @@ export default class PobMonorepoGenerator extends Generator {
|
|
|
232
245
|
message: "Would you like eslint in monorepo ?",
|
|
233
246
|
default: config ? config.eslint : true,
|
|
234
247
|
},
|
|
248
|
+
{
|
|
249
|
+
type: "confirm",
|
|
250
|
+
name: "storybook",
|
|
251
|
+
message: "Would you like storybook ?",
|
|
252
|
+
default: config ? config.storybook : detectStorybook(allPackages),
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
type: "confirm",
|
|
256
|
+
name: "storybookReactNative",
|
|
257
|
+
message: "Would you like the on-device react-native storybook ?",
|
|
258
|
+
default: config
|
|
259
|
+
? config.storybookReactNative
|
|
260
|
+
: detectStorybookReactNative(allPackages),
|
|
261
|
+
},
|
|
235
262
|
]);
|
|
236
263
|
this.pobMonorepoConfig.packageNames = this.packageNames;
|
|
237
264
|
this.config.set("monorepo", this.pobMonorepoConfig);
|
|
@@ -320,7 +347,8 @@ export default class PobMonorepoGenerator extends Generator {
|
|
|
320
347
|
this.composeWith("pob:common:format-lint", {
|
|
321
348
|
monorepo: true,
|
|
322
349
|
documentation: this.pobMonorepoConfig.documentation,
|
|
323
|
-
storybook:
|
|
350
|
+
storybook: this.pobMonorepoConfig.storybook,
|
|
351
|
+
storybookReactNative: this.pobMonorepoConfig.storybookReactNative,
|
|
324
352
|
typescript: this.pobMonorepoConfig.typescript,
|
|
325
353
|
build: hasRootBuild,
|
|
326
354
|
testing: this.pobMonorepoConfig.testing,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readdirSync } from "node:fs";
|
|
2
2
|
import Generator from "yeoman-generator";
|
|
3
3
|
import { latestLTS } from "../../../utils/nodeVersions.js";
|
|
4
4
|
import * as packageUtils from "../../../utils/package.js";
|
|
@@ -6,6 +6,9 @@ import { packageManagerRun } from "../../../utils/packageManagerUtils.js";
|
|
|
6
6
|
import { copyAndFormatTpl } from "../../../utils/writeAndFormat.js";
|
|
7
7
|
|
|
8
8
|
const rootConfigExtensionsRegex = /\.config\.(?:ts|mts|cts)$/;
|
|
9
|
+
// .js scripts count too: tsc then fails on them, which flags their migration
|
|
10
|
+
// to typescript
|
|
11
|
+
const scriptExtensionsRegex = /\.[cm]?[jt]s$/;
|
|
9
12
|
|
|
10
13
|
const hasRootConfigFiles = (rootPath) => {
|
|
11
14
|
try {
|
|
@@ -17,6 +20,17 @@ const hasRootConfigFiles = (rootPath) => {
|
|
|
17
20
|
}
|
|
18
21
|
};
|
|
19
22
|
|
|
23
|
+
// a scripts/ dir with only shell scripts gives tsc no input (TS18003)
|
|
24
|
+
const hasScriptFiles = (scriptsPath) => {
|
|
25
|
+
try {
|
|
26
|
+
return readdirSync(scriptsPath, { recursive: true }).some((name) =>
|
|
27
|
+
scriptExtensionsRegex.test(name),
|
|
28
|
+
);
|
|
29
|
+
} catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
20
34
|
export default class MonorepoTypescriptGenerator extends Generator {
|
|
21
35
|
constructor(args, opts) {
|
|
22
36
|
super(args, opts);
|
|
@@ -75,7 +89,7 @@ export default class MonorepoTypescriptGenerator extends Generator {
|
|
|
75
89
|
#hasTools() {
|
|
76
90
|
return (
|
|
77
91
|
hasRootConfigFiles(this.destinationPath()) ||
|
|
78
|
-
|
|
92
|
+
hasScriptFiles(this.destinationPath("scripts"))
|
|
79
93
|
);
|
|
80
94
|
}
|
|
81
95
|
|
|
@@ -101,22 +115,26 @@ export default class MonorepoTypescriptGenerator extends Generator {
|
|
|
101
115
|
|
|
102
116
|
// "typescript" is aliased to the typescript 6 api package, still required by
|
|
103
117
|
// typescript-eslint and typedoc. "@typescript/native" is typescript 7, which
|
|
104
|
-
// provides the "tsc" binary.
|
|
118
|
+
// provides the "tsc" binary, kept for the "tsc:go" script. "tsrs" is the
|
|
119
|
+
// rust port of typescript 7, used by all the other scripts.
|
|
105
120
|
packageUtils.addOrRemoveDevDependencies(
|
|
106
121
|
pkg,
|
|
107
122
|
pkg.name === "@pob/eslint-config-monorepo" || this.options.enable,
|
|
108
|
-
["typescript", "@typescript/native"],
|
|
123
|
+
["typescript", "@typescript/native", "tsrs"],
|
|
109
124
|
);
|
|
110
125
|
|
|
111
126
|
if (this.options.enable) {
|
|
127
|
+
// tsrs and tsc do not share their .tsbuildinfo: switching between them
|
|
128
|
+
// triggers a full rebuild
|
|
112
129
|
packageUtils.addOrRemoveScripts(pkg, this.#hasTypescriptProjects(), {
|
|
113
|
-
tsc: "
|
|
130
|
+
tsc: "tsrs -b",
|
|
131
|
+
"tsc:go": "tsc -b",
|
|
114
132
|
});
|
|
115
133
|
packageUtils.addOrRemoveScripts(
|
|
116
134
|
pkg,
|
|
117
135
|
!this.options.isAppProject && !this.options.checkOnly,
|
|
118
136
|
{
|
|
119
|
-
"build:definitions": "
|
|
137
|
+
"build:definitions": "tsrs -b",
|
|
120
138
|
},
|
|
121
139
|
);
|
|
122
140
|
|
|
@@ -134,6 +152,7 @@ export default class MonorepoTypescriptGenerator extends Generator {
|
|
|
134
152
|
}
|
|
135
153
|
} else if (pkg.scripts) {
|
|
136
154
|
delete pkg.scripts.tsc;
|
|
155
|
+
delete pkg.scripts["tsc:go"];
|
|
137
156
|
if (
|
|
138
157
|
pkg.scripts.postbuild === "tsc -b tsconfig.build.json" ||
|
|
139
158
|
pkg.scripts.postbuild === "tsc -b"
|
|
@@ -186,7 +186,11 @@ export default class MonorepoWorkspacesGenerator extends Generator {
|
|
|
186
186
|
);
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
|
|
189
|
+
// packages are updated in the install phase, after root files are written and
|
|
190
|
+
// before the root install of the end phase (see CorePnpmGenerator,
|
|
191
|
+
// CoreYarnGenerator, CoreBunGenerator), so the lockfile includes the
|
|
192
|
+
// dependencies updated in packages
|
|
193
|
+
install() {
|
|
190
194
|
this.packagePaths.forEach((packagePath) => {
|
|
191
195
|
if (
|
|
192
196
|
!existsSync(`${packagePath}/.yo-rc.json`) &&
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the project uses Claude Design sync: its tracked config lives in
|
|
3
|
+
* ".design-sync", next to the untracked ".ds-sync" cache and "ds-bundle"
|
|
4
|
+
* build output.
|
|
5
|
+
*
|
|
6
|
+
* @param {import("yeoman-generator").default} generator
|
|
7
|
+
*/
|
|
8
|
+
export default function hasDesignSync(generator) {
|
|
9
|
+
return generator.fs.exists(
|
|
10
|
+
generator.destinationPath(".design-sync/config.json"),
|
|
11
|
+
);
|
|
12
|
+
}
|
package/lib/utils/nodeEngines.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import pobDependencies from "pob-dependencies";
|
|
1
2
|
import semver from "semver";
|
|
2
3
|
import { latestLTS, maintenanceLTS } from "./nodeVersions.js";
|
|
3
4
|
import * as packageUtils from "./package.js";
|
|
@@ -26,22 +27,31 @@ export const getEnvsMinNodeMajor = (envs, onlyLatestLTS) => {
|
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
|
-
* Min
|
|
30
|
+
* Min version of a range, undefined when missing or not parseable
|
|
30
31
|
* (workspace:*, catalog:, npm: alias...).
|
|
31
32
|
*/
|
|
32
|
-
|
|
33
|
+
const getMinVersion = (range) => {
|
|
33
34
|
if (!range) return undefined;
|
|
34
35
|
try {
|
|
35
|
-
|
|
36
|
-
return minVersion ? semver.major(minVersion) : undefined;
|
|
36
|
+
return semver.minVersion(range) ?? undefined;
|
|
37
37
|
} catch {
|
|
38
38
|
return undefined;
|
|
39
39
|
}
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
43
|
+
* Min node major of a range, undefined when missing or not parseable
|
|
44
|
+
* (workspace:*, catalog:, npm: alias...).
|
|
45
|
+
*/
|
|
46
|
+
export const getMinMajor = (range) => {
|
|
47
|
+
const minVersion = getMinVersion(range);
|
|
48
|
+
return minVersion ? semver.major(minVersion) : undefined;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* engines.node value for a min node major. An engines.node with a higher min
|
|
53
|
+
* version is kept, to guarantee a node version with a security fix: within
|
|
54
|
+
* the min major when envs are defined, any higher version otherwise.
|
|
45
55
|
*/
|
|
46
56
|
export const resolveEnginesNode = (
|
|
47
57
|
currentEnginesNode,
|
|
@@ -56,11 +66,13 @@ export const resolveEnginesNode = (
|
|
|
56
66
|
throw new Error(`Invalid min node version: ${minNodeMajor}`);
|
|
57
67
|
}
|
|
58
68
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
69
|
+
const currentMinVersion = getMinVersion(currentEnginesNode);
|
|
70
|
+
if (
|
|
71
|
+
currentMinVersion &&
|
|
72
|
+
semver.gt(currentMinVersion, minVersion) &&
|
|
73
|
+
(!hasEnvs || semver.major(currentMinVersion) === Number(major))
|
|
74
|
+
) {
|
|
75
|
+
return currentEnginesNode;
|
|
64
76
|
}
|
|
65
77
|
|
|
66
78
|
return `>=${minVersion}`;
|
|
@@ -68,7 +80,9 @@ export const resolveEnginesNode = (
|
|
|
68
80
|
|
|
69
81
|
/**
|
|
70
82
|
* Updates "@types/node" when it is lower than engines.node min major.
|
|
71
|
-
* Never adds it, never lowers devDependencies.
|
|
83
|
+
* Never adds it, never lowers devDependencies. A pinned devDependency stays
|
|
84
|
+
* pinned (check-package-dependencies/require-pinned-versions), with the
|
|
85
|
+
* pob-dependencies version when it satisfies the min major.
|
|
72
86
|
*/
|
|
73
87
|
export const updateTypesNodeFromEngines = (pkg) => {
|
|
74
88
|
const minMajor = getMinMajor(pkg.engines?.node);
|
|
@@ -83,7 +97,12 @@ export const updateTypesNodeFromEngines = (pkg) => {
|
|
|
83
97
|
if (currentDevVersion) {
|
|
84
98
|
const currentMinMajor = getMinMajor(currentDevVersion);
|
|
85
99
|
if (currentMinMajor !== undefined && currentMinMajor < minMajor) {
|
|
86
|
-
|
|
100
|
+
const pinnedVersion = pobDependencies["@types/node"];
|
|
101
|
+
pkg.devDependencies["@types/node"] =
|
|
102
|
+
semver.valid(currentDevVersion) &&
|
|
103
|
+
semver.major(pinnedVersion) >= minMajor
|
|
104
|
+
? pinnedVersion
|
|
105
|
+
: range;
|
|
87
106
|
}
|
|
88
107
|
}
|
|
89
108
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
+
import pobDependencies from "pob-dependencies";
|
|
2
3
|
import {
|
|
3
4
|
resolveEnginesNode,
|
|
4
5
|
updateNodeEngines,
|
|
@@ -6,13 +7,24 @@ import {
|
|
|
6
7
|
} from "./nodeEngines.js";
|
|
7
8
|
|
|
8
9
|
describe("updateTypesNodeFromEngines", () => {
|
|
9
|
-
it("
|
|
10
|
+
it("keeps pinned devDependencies pinned when lower than engines min major", () => {
|
|
10
11
|
const pkg = {
|
|
11
12
|
engines: { node: ">=24.14.1" },
|
|
12
13
|
devDependencies: { "@types/node": "22.5.0" },
|
|
13
14
|
};
|
|
14
15
|
updateTypesNodeFromEngines(pkg);
|
|
15
|
-
expect(pkg.devDependencies["@types/node"]).toBe(
|
|
16
|
+
expect(pkg.devDependencies["@types/node"]).toBe(
|
|
17
|
+
pobDependencies["@types/node"],
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("uses a range when the pinned version is lower than engines min major", () => {
|
|
22
|
+
const pkg = {
|
|
23
|
+
engines: { node: ">=99.0.0" },
|
|
24
|
+
devDependencies: { "@types/node": "22.5.0" },
|
|
25
|
+
};
|
|
26
|
+
updateTypesNodeFromEngines(pkg);
|
|
27
|
+
expect(pkg.devDependencies["@types/node"]).toBe(">=99.0.0");
|
|
16
28
|
});
|
|
17
29
|
|
|
18
30
|
it("keeps devDependencies with the same major", () => {
|
|
@@ -114,6 +126,17 @@ describe("resolveEnginesNode", () => {
|
|
|
114
126
|
it("lets envs lower engines.node", () => {
|
|
115
127
|
expect(resolveEnginesNode(">=24.14.1", "22", true)).toBe(">=22.18.0");
|
|
116
128
|
});
|
|
129
|
+
|
|
130
|
+
it.each([true, false])(
|
|
131
|
+
"keeps a higher min version of the same major (hasEnvs: %s)",
|
|
132
|
+
(hasEnvs) => {
|
|
133
|
+
expect(resolveEnginesNode(">=24.15.3", "24", hasEnvs)).toBe(">=24.15.3");
|
|
134
|
+
},
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
it("raises a lower min version of the same major", () => {
|
|
138
|
+
expect(resolveEnginesNode(">=24.0.0", "24", true)).toBe(">=24.14.1");
|
|
139
|
+
});
|
|
117
140
|
});
|
|
118
141
|
|
|
119
142
|
describe("updateNodeEngines", () => {
|
|
@@ -124,7 +147,9 @@ describe("updateNodeEngines", () => {
|
|
|
124
147
|
};
|
|
125
148
|
updateNodeEngines(pkg, {});
|
|
126
149
|
expect(pkg.engines.node).toBe(">=24.14.1");
|
|
127
|
-
expect(pkg.devDependencies["@types/node"]).toBe(
|
|
150
|
+
expect(pkg.devDependencies["@types/node"]).toBe(
|
|
151
|
+
pobDependencies["@types/node"],
|
|
152
|
+
);
|
|
128
153
|
});
|
|
129
154
|
|
|
130
155
|
it("supports babelEnvs", () => {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Fallbacks for the storybook options of a config missing them.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param {Record<string, any>[]} pkgs
|
|
5
|
+
* @param {(name: string) => boolean} test
|
|
6
|
+
*/
|
|
7
|
+
const someDependency = (pkgs, test) =>
|
|
8
|
+
pkgs.some((pkg) =>
|
|
9
|
+
[pkg.dependencies, pkg.devDependencies].some(
|
|
10
|
+
(dependencies) => dependencies && Object.keys(dependencies).some(test),
|
|
11
|
+
),
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
// a web storybook depends on its framework (@storybook/react-vite,
|
|
15
|
+
// @storybook/nextjs...): "storybook" alone is also a dependency of the
|
|
16
|
+
// react-native one
|
|
17
|
+
const webFrameworkRegExp =
|
|
18
|
+
/^@storybook\/(?:.+-(?:vite|webpack5)|nextjs|angular|ember|sveltekit)$/;
|
|
19
|
+
|
|
20
|
+
/** @param {Record<string, any>[]} pkgs */
|
|
21
|
+
export const detectStorybook = (pkgs) =>
|
|
22
|
+
someDependency(pkgs, (name) => webFrameworkRegExp.test(name));
|
|
23
|
+
|
|
24
|
+
/** @param {Record<string, any>[]} pkgs */
|
|
25
|
+
export const detectStorybookReactNative = (pkgs) =>
|
|
26
|
+
someDependency(pkgs, (name) => name === "@storybook/react-native");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pob",
|
|
3
|
-
"version": "40.
|
|
3
|
+
"version": "40.3.0",
|
|
4
4
|
"description": "Pile of bones, library generator with git/babel/typescript/typedoc/readme/vitest",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"skeleton"
|
|
@@ -31,13 +31,13 @@
|
|
|
31
31
|
"./package.json": "./package.json"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@pob/codemods": "0.18.
|
|
34
|
+
"@pob/codemods": "0.18.1",
|
|
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",
|
|
38
38
|
"@pob/sort-pkg": "13.2.0",
|
|
39
39
|
"@types/inquirer": "9.0.10",
|
|
40
|
-
"@yeoman/adapter": "4.0.
|
|
40
|
+
"@yeoman/adapter": "4.0.3",
|
|
41
41
|
"eslint": "10.12.0",
|
|
42
42
|
"findup-sync": "^5.0.0",
|
|
43
43
|
"git-remote-url": "^1.0.1",
|
|
@@ -51,18 +51,19 @@
|
|
|
51
51
|
"minimist": "1.2.8",
|
|
52
52
|
"oxfmt": "0.72.0",
|
|
53
53
|
"parse-author": "2.0.0",
|
|
54
|
-
"pob-dependencies": "28.
|
|
54
|
+
"pob-dependencies": "28.2.0",
|
|
55
55
|
"semver": "7.8.5",
|
|
56
56
|
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
57
57
|
"validate-npm-package-name": "^8.0.0",
|
|
58
58
|
"yeoman-environment": "6.3.0",
|
|
59
|
-
"yeoman-generator": "10.0
|
|
59
|
+
"yeoman-generator": "10.3.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@pob/root": "28.1
|
|
62
|
+
"@pob/root": "28.2.1",
|
|
63
63
|
"@types/node": "24.19.1",
|
|
64
64
|
"@typescript/native": "npm:typescript@7.0.2",
|
|
65
|
-
"@yeoman/types": "1.13.1"
|
|
65
|
+
"@yeoman/types": "1.13.1",
|
|
66
|
+
"tsrs": "0.18.0-ts7.1.0-dev.20260929"
|
|
66
67
|
},
|
|
67
68
|
"engines": {
|
|
68
69
|
"node": ">=24.14.1"
|
|
@@ -72,10 +73,11 @@
|
|
|
72
73
|
},
|
|
73
74
|
"scripts": {
|
|
74
75
|
"build": "pnpm run build:definitions",
|
|
75
|
-
"build:definitions": "
|
|
76
|
+
"build:definitions": "tsrs -p tsconfig.json",
|
|
76
77
|
"lint": "pnpm run lint:oxlint && pnpm run lint:eslint",
|
|
77
78
|
"lint:eslint": "pnpm --dir '../..' exec eslint --quiet 'packages/pob'",
|
|
78
79
|
"lint:oxlint": "pnpm --dir '../..' exec oxlint --quiet 'packages/pob'",
|
|
79
|
-
"tsc": "
|
|
80
|
+
"tsc": "tsrs",
|
|
81
|
+
"tsc:go": "tsc"
|
|
80
82
|
}
|
|
81
83
|
}
|