pob 35.6.0 → 36.0.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.
Files changed (28) hide show
  1. package/README.md +2 -21
  2. package/lib/generators/app/ignorePaths.js +1 -1
  3. package/lib/generators/common/babel/CommonBabelGenerator.js +7 -12
  4. package/lib/generators/common/format-lint/CommonLintGenerator.js +6 -0
  5. package/lib/generators/common/release/templates/workflow-release.yml.ejs +1 -1
  6. package/lib/generators/common/testing/CommonTestingGenerator.js +26 -19
  7. package/lib/generators/common/transpiler/CommonTranspilerGenerator.js +0 -1
  8. package/lib/generators/core/ci/templates/github-action-documentation-workflow.yml.ejs +1 -1
  9. package/lib/generators/core/ci/templates/github-action-push-workflow-split.yml.ejs +6 -6
  10. package/lib/generators/core/ci/templates/github-action-push-workflow.yml.ejs +1 -1
  11. package/lib/generators/core/claude/CoreClaudeGenerator.js +73 -0
  12. package/lib/generators/core/package/CorePackageGenerator.js +20 -63
  13. package/lib/generators/core/pnpm/CorePnpmGenerator.js +7 -6
  14. package/lib/generators/core/vscode/CoreVSCodeGenerator.js +1 -1
  15. package/lib/generators/core/vscode/templates/settings.json.ejs +0 -6
  16. package/lib/generators/core/yarn/CoreYarnGenerator.js +7 -7
  17. package/lib/generators/monorepo/PobMonorepoGenerator.js +8 -14
  18. package/lib/generators/monorepo/typescript/MonorepoTypescriptGenerator.js +36 -0
  19. package/lib/generators/monorepo/typescript/templates/tsconfig.json.ejs +3 -0
  20. package/lib/generators/monorepo/typescript/templates/tsconfig.root-configs.json.ejs +13 -0
  21. package/lib/generators/monorepo/workspaces/MonorepoWorkspacesGenerator.js +4 -1
  22. package/lib/generators/pob/PobBaseGenerator.js +4 -0
  23. package/lib/pob.js +6 -0
  24. package/lib/utils/package.js +0 -26
  25. package/package.json +11 -11
  26. package/lib/generators/common/testing/templates/babel.config.cjs.ejs +0 -26
  27. package/lib/generators/core/package/templates/check-package.js.ejs +0 -3
  28. package/lib/generators/core/package/templates/check-packages.js.ejs +0 -7
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  </h1>
4
4
 
5
5
  <p align="center">
6
- Pile of bones, library generator with git/babel/typescript/typedoc/readme/jest
6
+ Pile of bones, library generator with git/babel/typescript/typedoc/readme/vitest
7
7
  </p>
8
8
 
9
9
  <p align="center">
@@ -28,30 +28,11 @@ You can now use `yarn run watch` !
28
28
 
29
29
  ### How this works
30
30
 
31
- #### Babel
32
-
33
- Write code in the `src` directory, it's then transpiled with babel and rollup to `dist`.
34
- Use the task `yarn run build` or `yarn run watch` to transpile the code.
35
-
36
- There are several environments: `node`, `browser`.
37
- For each of these environments, there is also a `dev` version that add flow runtime checks.
38
-
39
31
  #### Coding Rules
40
32
 
41
33
  Eslint is used to ensure a common coding style. I mostly follow the [Airbnb coding style](https://github.com/airbnb/javascript/blob/master/README.md).
42
34
  You can check the code by running the task `yarn run lint`. With an editor, install the plugins to validate the code as you type !
43
35
 
44
- #### Documentation
45
-
46
- [typedoc](https://typedoc.org/) allows to document the code and generate the api.
47
- [jest](https://www.npmjs.com/package/jest) is used to generate the coverage.
48
-
49
- Documentation can be generated by github actions and pushed to github-pages.
50
-
51
- #### Tests
52
-
53
- Tests are in the directory `src` with jest. Use the task `yarn test` to run the tests with jest.
54
-
55
36
  ### Available tasks with `yarn run`
56
37
 
57
38
  #### Code, Transpile, Lint
@@ -59,7 +40,7 @@ Tests are in the directory `src` with jest. Use the task `yarn test` to run the
59
40
  - `build`: `clean` the directory, build `src` to `dist` with rollup
60
41
  - `watch`: `clean` then build and watch with rollup
61
42
  - `lint`: execute `eslint`
62
- - `test`: run tests with jest
43
+ - `test`: run tests
63
44
 
64
45
  ### Generate documentation
65
46
 
@@ -20,10 +20,10 @@ export const appIgnorePaths = {
20
20
  storybook: (config) => ["/.storybook/storybook.requires.ts"],
21
21
  expo: (config) => [
22
22
  "/.expo/",
23
- "/src/tamagui-web.css",
24
23
  "/android/",
25
24
  "/ios/",
26
25
  "/dist/",
26
+ "/dist-native/",
27
27
  "*.jks",
28
28
  "*.p8",
29
29
  "*.p12",
@@ -304,6 +304,12 @@ export default class CommonBabelGenerator extends Generator {
304
304
  (env) => env.target === "browser",
305
305
  );
306
306
 
307
+ if (useBabel) {
308
+ throw new Error(
309
+ "pob-babel is deprecated. Use @pob/rollup-esbuild or @pob/rollup-typescript instead.",
310
+ );
311
+ }
312
+
307
313
  /* dependencies */
308
314
 
309
315
  if (
@@ -324,11 +330,6 @@ export default class CommonBabelGenerator extends Generator {
324
330
  if (pkg.dependencies && pkg.dependencies["pob-babel"]) {
325
331
  throw new Error("pob-babel is deprecated.");
326
332
  }
327
- if (pkg.dependencies && pkg.dependencies["@babel/runtime"]) {
328
- // update pob-babel in alp-dev
329
- packageUtils.addDependencies(pkg, ["@babel/runtime"], "^");
330
- }
331
-
332
333
  const isLibraryRollupPlugin = pkg.name.includes("rollup-plugin");
333
334
 
334
335
  packageUtils.addOrRemoveDevDependencies(
@@ -440,13 +441,7 @@ export default class CommonBabelGenerator extends Generator {
440
441
  this.fs.delete(".babelrc");
441
442
  this.fs.delete("babel.config.json");
442
443
  this.fs.delete("babel.config.mjs");
443
- if (this.fs.exists(this.destinationPath("babel.config.js"))) {
444
- this.fs.move(
445
- this.destinationPath("babel.config.js"),
446
- this.destinationPath("babel.config.cjs"),
447
- );
448
- }
449
-
444
+ this.fs.delete("babel.config.js");
450
445
  this.fs.writeJSON(this.destinationPath("package.json"), pkg);
451
446
  }
452
447
  }
@@ -409,6 +409,12 @@ export default class CommonFormatLintGenerator extends Generator {
409
409
  };
410
410
  })();
411
411
 
412
+ const isMonorepoRoot =
413
+ this.options.monorepo || Boolean(inMonorepo && inMonorepo.root);
414
+ if (isMonorepoRoot && useTypescript) {
415
+ flatCascade.push("...pobConfig(import.meta.url).configs.monorepo");
416
+ }
417
+
412
418
  const eslintrcBadPath = this.destinationPath(".eslintrc");
413
419
  this.fs.delete(eslintrcBadPath);
414
420
  this.fs.delete(`${eslintrcBadPath}.yml`);
@@ -55,7 +55,7 @@ jobs:
55
55
  version: 11
56
56
  <% } -%>
57
57
 
58
- - uses: actions/setup-node@v6
58
+ - uses: actions/setup-node@v7
59
59
  with:
60
60
  node-version: <%= nodeLatestMajorVersion %>
61
61
  registry-url: "https://registry.npmjs.org"
@@ -30,7 +30,7 @@ export default class CommonTestingGenerator extends Generator {
30
30
  this.option("runner", {
31
31
  type: String,
32
32
  default: "node",
33
- description: "test runner (jest or node)",
33
+ description: "test runner (vitest or node)",
34
34
  });
35
35
 
36
36
  this.option("ci", {
@@ -157,14 +157,14 @@ export default class CommonTestingGenerator extends Generator {
157
157
  (inMonorepo && inMonorepo.pobMonorepoConfig) || {};
158
158
  const globalTesting = yoConfigPobMonorepo && yoConfigPobMonorepo.testing;
159
159
  const enableForMonorepo = this.options.monorepo && globalTesting;
160
- const transpileWithEsbuild = packageUtils.transpileWithEsbuild(pkg);
160
+ const transpileWithEsbuild = false;
161
161
  const transpileWithBabel = transpileWithEsbuild
162
162
  ? false
163
163
  : // eslint-disable-next-line unicorn/no-nested-ternary
164
164
  this.options.monorepo
165
165
  ? yoConfigPobMonorepo.typescript &&
166
166
  yoConfigPobMonorepo.typescript !== "check-only"
167
- : packageUtils.transpileWithBabel(pkg);
167
+ : false;
168
168
  const withTypescript =
169
169
  transpileWithBabel ||
170
170
  pkg.pob?.bundler === "tsc" ||
@@ -259,21 +259,28 @@ export default class CommonTestingGenerator extends Generator {
259
259
  }
260
260
  const experimentalTestCoverage =
261
261
  pkg.name === "check-package-dependencies";
262
- return `TZ=UTC ${
263
- coverage && !experimentalTestCoverage
264
- ? `npx c8${
265
- coverage === "generate"
266
- ? ` --reporter=${coverage === "generate" ? "json" : "lcov"}`
267
- : ""
268
- } --all --src ./${this.options.srcDirectory} `
269
- : ""
270
- }node ${
271
- this.options.typescript
272
- ? `${tsTestLoaderOption ? `${tsTestLoaderOption} ` : ""}`
273
- : ""
274
- }${this.fs.exists("src/test-setup.ts") ? "--import ./src/test-setup.ts " : ""}--test${experimentalTestCoverage && coverage ? ` --experimental-test-coverage${coverage === "generate" ? " --test-reporter=spec --test-reporter-destination=stdout --test-reporter=lcov --test-reporter-destination=docs/coverage.lcov" : ""} --test-coverage-include="${this.options.srcDirectory}/**/*.ts"` : ""} '${this.options.monorepo ? `${workspacesPattern}/*/` : ""}${`${
275
- hasTestFolder ? "test/*" : `${this.options.srcDirectory}/**/*.test`
276
- }.${this.options.typescript ? "ts" : "js"}`}'`;
262
+ return [
263
+ experimentalTestCoverage && coverage === "generate"
264
+ ? "mkdir -p docs && "
265
+ : "",
266
+ `TZ=UTC ${
267
+ coverage && !experimentalTestCoverage
268
+ ? `npx c8${
269
+ coverage === "generate"
270
+ ? ` --reporter=${coverage === "generate" ? "json" : "lcov"}`
271
+ : ""
272
+ } --all --src ./${this.options.srcDirectory} `
273
+ : ""
274
+ }node ${
275
+ this.options.typescript
276
+ ? `${tsTestLoaderOption ? `${tsTestLoaderOption} ` : ""}`
277
+ : ""
278
+ }${this.fs.exists("src/test-setup.ts") ? "--import ./src/test-setup.ts " : ""}--test${experimentalTestCoverage && coverage ? ` --experimental-test-coverage${coverage === "generate" ? " --test-reporter=spec --test-reporter-destination=stdout --test-reporter=lcov --test-reporter-destination=docs/coverage.lcov" : ""} --test-coverage-include="${this.options.srcDirectory}/**/*.ts"` : ""} '${this.options.monorepo ? `${workspacesPattern}/*/` : ""}${`${
279
+ hasTestFolder
280
+ ? "test/*"
281
+ : `${this.options.srcDirectory}/**/*.test`
282
+ }.${this.options.typescript ? "ts" : "js"}`}'`,
283
+ ].join("");
277
284
  }
278
285
  case "bun": {
279
286
  if (this.options.packageManager !== "bun") {
@@ -389,7 +396,7 @@ export default class CommonTestingGenerator extends Generator {
389
396
  }),
390
397
  "test:coverage:generate": createTestCommand({
391
398
  workspacesPattern,
392
- coverageJson: true,
399
+ coverage: "generate",
393
400
  }),
394
401
  });
395
402
  } else {
@@ -160,7 +160,6 @@ export default class CommonTranspilerGenerator extends Generator {
160
160
  const cleanCommand = (() => {
161
161
  if (bundler === "rollup-typescript") return "pob-typescript-clean-out";
162
162
  if (bundler === "rollup-esbuild") return "pob-esbuild-clean-out";
163
- if (bundler === "rollup-babel") return "pob-babel-clean-out";
164
163
  if (bundler === "esbuild") return "pob-esbuild-clean-out";
165
164
  if (bundler === "tsc") return "rm -Rf";
166
165
  if (bundler) throw new Error(`Invalid bundler: ${bundler}`);
@@ -27,7 +27,7 @@ jobs:
27
27
  version: 11
28
28
 
29
29
  <% } -%>
30
- - uses: actions/setup-node@v6
30
+ - uses: actions/setup-node@v7
31
31
  with:
32
32
  node-version: <%= nodeLatestMajorVersion %>
33
33
 
@@ -28,7 +28,7 @@ jobs:
28
28
  version: 11
29
29
 
30
30
  <% } -%>
31
- - uses: actions/setup-node@v6
31
+ - uses: actions/setup-node@v7
32
32
  with:
33
33
  node-version: <%= nodeLatestMajorVersion %>
34
34
 
@@ -73,7 +73,7 @@ jobs:
73
73
  version: 11
74
74
 
75
75
  <% } -%>
76
- - uses: actions/setup-node@v6
76
+ - uses: actions/setup-node@v7
77
77
  with:
78
78
  node-version: <%= nodeLatestMajorVersion %>
79
79
 
@@ -120,7 +120,7 @@ jobs:
120
120
  version: 11
121
121
 
122
122
  <% } -%>
123
- - uses: actions/setup-node@v6
123
+ - uses: actions/setup-node@v7
124
124
  with:
125
125
  node-version: <%= nodeLatestMajorVersion %>
126
126
 
@@ -178,7 +178,7 @@ jobs:
178
178
  version: 11
179
179
 
180
180
  <% } -%>
181
- - uses: actions/setup-node@v6
181
+ - uses: actions/setup-node@v7
182
182
  with:
183
183
  node-version: ${{ matrix.node-version }}
184
184
 
@@ -249,7 +249,7 @@ jobs:
249
249
  version: 11
250
250
 
251
251
  <% } -%>
252
- - uses: actions/setup-node@v6
252
+ - uses: actions/setup-node@v7
253
253
  with:
254
254
  node-version: ${{ matrix.node-version }}
255
255
 
@@ -280,7 +280,7 @@ jobs:
280
280
  steps:
281
281
  - uses: actions/checkout@v7
282
282
 
283
- - uses: actions/setup-node@v6
283
+ - uses: actions/setup-node@v7
284
284
  with:
285
285
  node-version: <%= nodeLatestMajorVersion %>
286
286
 
@@ -32,7 +32,7 @@ jobs:
32
32
 
33
33
  <% } -%>
34
34
  - name: Use Node.js ${{ matrix.node-version }}
35
- uses: actions/setup-node@v6
35
+ uses: actions/setup-node@v7
36
36
  with:
37
37
  node-version: ${{ matrix.node-version }}
38
38
  registry-url: 'https://registry.npmjs.org'
@@ -0,0 +1,73 @@
1
+ import Generator from "yeoman-generator";
2
+ import { writeAndFormatJson } from "../../../utils/writeAndFormat.js";
3
+
4
+ export default class CoreClaudeGenerator extends Generator {
5
+ constructor(args, opts) {
6
+ super(args, opts);
7
+
8
+ this.option("root", {
9
+ type: Boolean,
10
+ required: false,
11
+ default: true,
12
+ description: "Root package.",
13
+ });
14
+ }
15
+
16
+ async writing() {
17
+ const pkg = this.fs.readJSON(this.destinationPath("package.json"), {});
18
+ const claudeGitignorePath = this.destinationPath(".claude/.gitignore");
19
+ const claudeSettingsPath = this.destinationPath(".claude/settings.json");
20
+
21
+ if (!this.options.root) {
22
+ this.fs.delete(claudeGitignorePath);
23
+ this.fs.delete(claudeSettingsPath);
24
+ return;
25
+ }
26
+
27
+ this.fs.write(
28
+ claudeGitignorePath,
29
+ "/settings.local.json\n/skills/local.*\n",
30
+ );
31
+
32
+ const command =
33
+ pkg.name === "pob-monorepo"
34
+ ? "node ./@pob/root/bin/pob-claude-run-lint-staged.js"
35
+ : "./node_modules/.bin/pob-claude-run-lint-staged";
36
+
37
+ const claudePostToolUseHook = {
38
+ matcher: "Edit|Write|MultiEdit",
39
+ hooks: [{ type: "command", command }],
40
+ };
41
+
42
+ const existing = this.fs.readJSON(claudeSettingsPath, {
43
+ hooks: {
44
+ PostToolUse: [claudePostToolUseHook],
45
+ },
46
+ });
47
+
48
+ // Find or create the PostToolUse hook entry for our matcher
49
+ const postToolUse = existing.hooks?.PostToolUse ?? [];
50
+
51
+ const existingEntry = postToolUse.find(
52
+ (entry) => entry.matcher === claudePostToolUseHook.matcher,
53
+ );
54
+ if (existingEntry) {
55
+ // Add any of our hooks not already present
56
+ for (const hook of claudePostToolUseHook.hooks) {
57
+ if (!existingEntry.hooks?.some((h) => h.command === hook.command)) {
58
+ (existingEntry.hooks ??= []).push(hook);
59
+ }
60
+ }
61
+ } else {
62
+ postToolUse.push(claudePostToolUseHook);
63
+ }
64
+
65
+ await writeAndFormatJson(this.fs, claudeSettingsPath, {
66
+ ...existing,
67
+ hooks: {
68
+ ...existing.hooks,
69
+ PostToolUse: postToolUse,
70
+ },
71
+ });
72
+ }
73
+ }
@@ -221,28 +221,29 @@ export default class CorePackageGenerator extends Generator {
221
221
  fs.unlinkSync(this.destinationPath("yarn-error.log"));
222
222
  }
223
223
 
224
- if (this.options.inMonorepo && !this.options.isRoot) {
225
- packageUtils.removeScripts(pkg, ["checks"]);
224
+ if (pkg.name !== "@pob/root") {
226
225
  packageUtils.removeDevDependencies(pkg, ["check-package-dependencies"]);
227
- } else if (this.options.isMonorepo && this.options.isRoot) {
228
- const doesMjsCheckPackagesExists = this.fs.exists(
229
- this.destinationPath("scripts/check-packages.mjs"),
230
- );
231
- const doesJsCheckPackagesExists = this.fs.exists(
232
- this.destinationPath("scripts/check-packages.js"),
233
- );
226
+ }
227
+ if (this.fs.exists(this.destinationPath("scripts/check-packages.mjs"))) {
228
+ this.fs.delete(this.destinationPath("scripts/check-packages.mjs"));
229
+ }
230
+ if (this.fs.exists(this.destinationPath("scripts/check-packages.js"))) {
231
+ this.fs.delete(this.destinationPath("scripts/check-packages.js"));
232
+ }
234
233
 
235
- if (doesJsCheckPackagesExists || doesMjsCheckPackagesExists) {
236
- packageUtils.addDevDependencies(pkg, ["check-package-dependencies"]);
234
+ if (this.options.inMonorepo && !this.options.isRoot) {
235
+ packageUtils.removeScripts(pkg, ["checks"]);
236
+ } else if (this.options.isRoot) {
237
+ const checksScript = pkg.scripts?.checks;
238
+ if (checksScript && checksScript.includes("node scripts/check-package")) {
239
+ pkg.scripts.checks = checksScript.replace(
240
+ /( && )?node scripts\/check-package\.(mjs|js)( && )?/,
241
+ "",
242
+ );
243
+ if (pkg.scripts.checks === "") {
244
+ delete pkg.scripts.checks;
245
+ }
237
246
  }
238
-
239
- packageUtils.addOrRemoveScripts(
240
- pkg,
241
- doesMjsCheckPackagesExists || doesJsCheckPackagesExists,
242
- {
243
- checks: `node scripts/check-packages.${doesMjsCheckPackagesExists ? "mjs" : "js"}`,
244
- },
245
- );
246
247
  } else if (inMonorepo && !inMonorepo.root) {
247
248
  if (this.fs.exists("scripts/check-package.js")) {
248
249
  this.fs.delete("scripts/check-package.js");
@@ -251,50 +252,6 @@ export default class CorePackageGenerator extends Generator {
251
252
  this.fs.delete("scripts/check-package.mjs");
252
253
  }
253
254
  packageUtils.removeScripts(pkg, ["checks"]);
254
- } else {
255
- const doesMjsCheckPackageExists = this.fs.exists(
256
- this.destinationPath("scripts/check-package.mjs"),
257
- );
258
- let doesJsCheckPackageExists = this.fs.exists(
259
- this.destinationPath("scripts/check-package.js"),
260
- );
261
- const doesTsCheckPackageExists = this.fs.exists(
262
- this.destinationPath("scripts/check-package.ts"),
263
- );
264
-
265
- if (pkg.type === "module") {
266
- if (!doesJsCheckPackageExists && !doesTsCheckPackageExists) {
267
- doesJsCheckPackageExists = true;
268
- this.fs.copyTpl(
269
- this.templatePath("check-package.js.ejs"),
270
- this.destinationPath("scripts/check-package.ts"),
271
- {
272
- isLibrary: pkg.private !== true,
273
- },
274
- );
275
- }
276
- }
277
- if (
278
- doesJsCheckPackageExists ||
279
- doesMjsCheckPackageExists ||
280
- doesTsCheckPackageExists
281
- ) {
282
- packageUtils.addDevDependencies(pkg, ["check-package-dependencies"]);
283
- }
284
-
285
- packageUtils.addOrRemoveScripts(
286
- pkg,
287
- doesMjsCheckPackageExists ||
288
- doesJsCheckPackageExists ||
289
- doesTsCheckPackageExists,
290
- {
291
- checks: `node scripts/check-package.${(() => {
292
- if (doesMjsCheckPackageExists) return "mjs";
293
- if (doesTsCheckPackageExists) return "ts";
294
- return "js";
295
- })()}`,
296
- },
297
- );
298
255
  }
299
256
 
300
257
  if (!pkg.authors) {
@@ -1,5 +1,5 @@
1
1
  import sortObject from "@pob/sort-object";
2
- import yml from "js-yaml";
2
+ import { FAILSAFE_SCHEMA, dump, loadAll } from "js-yaml";
3
3
  import { lt } from "semver";
4
4
  import Generator from "yeoman-generator";
5
5
  import { writeAndFormat } from "../../../utils/writeAndFormat.js";
@@ -47,10 +47,10 @@ export default class CorePnpmGenerator extends Generator {
47
47
  this.destinationPath("pnpm-workspace.yaml"),
48
48
  { defaults: "" },
49
49
  );
50
- const config =
51
- yml.load(configString, {
52
- schema: yml.FAILSAFE_SCHEMA,
53
- }) || {};
50
+ const [loadedConfig] = loadAll(configString, {
51
+ schema: FAILSAFE_SCHEMA,
52
+ });
53
+ const config = loadedConfig ?? {};
54
54
 
55
55
  if (config.allowBuilds) {
56
56
  config.allowBuilds = Object.fromEntries(
@@ -70,11 +70,12 @@ export default class CorePnpmGenerator extends Generator {
70
70
  config.minimumReleaseAge = 1440 * 3; // 3 days in minutes
71
71
  config.minimumReleaseAgeExclude = minimumReleaseAgeExcludePackages;
72
72
  config.dedupePeerDependents = true;
73
+ config.nodeLinker = "hoisted";
73
74
 
74
75
  await writeAndFormat(
75
76
  this.fs,
76
77
  this.destinationPath("pnpm-workspace.yaml"),
77
- yml.dump(sortObject(config), { lineWidth: 9999, noCompatMode: true }),
78
+ dump(sortObject(config), { lineWidth: 9999 }),
78
79
  );
79
80
  } else {
80
81
  if (pkg.packageManager?.startsWith("pnpm@")) {
@@ -37,7 +37,7 @@ export default class CoreVSCodeGenerator extends Generator {
37
37
  this.option("testRunner", {
38
38
  type: String,
39
39
  required: false,
40
- description: "Test runner (jest, vitest, ...)",
40
+ description: "Test runner (node, vitest, ...)",
41
41
  });
42
42
 
43
43
  this.option("yarnNodeLinker", {
@@ -40,12 +40,6 @@
40
40
  "source.organizeImports": "never"
41
41
  },
42
42
 
43
-
44
- <% if (testing && module && (!testRunner || testRunner === 'jest')) { -%>
45
- // jest
46
- "jest.jestCommandLine": "NODE_OPTIONS=--experimental-vm-modules node_modules/.bin/jest",
47
- <% } -%>
48
-
49
43
  // extension eslint config
50
44
  "eslint.workingDirectories": ["."],
51
45
  "eslint.useFlatConfig": true,
@@ -1,7 +1,7 @@
1
1
  import fs from "node:fs";
2
2
  import { isDeepStrictEqual } from "node:util";
3
3
  import sortObject from "@pob/sort-object";
4
- import yml from "js-yaml";
4
+ import { FAILSAFE_SCHEMA, dump, loadAll } from "js-yaml";
5
5
  import { lt } from "semver";
6
6
  import Generator from "yeoman-generator";
7
7
  import { ensureJsonFileFormatted } from "../../../utils/ensureJsonFileFormatted.js";
@@ -154,11 +154,11 @@ export default class CoreYarnGenerator extends Generator {
154
154
 
155
155
  // must be done after plugins installed
156
156
  const configString = this.fs.read(".yarnrc.yml", { defaults: "" });
157
- const config =
158
- yml.load(configString, {
159
- schema: yml.FAILSAFE_SCHEMA,
160
- json: true,
161
- }) || {};
157
+ const [loadedConfig] = loadAll(configString, {
158
+ schema: FAILSAFE_SCHEMA,
159
+ json: true,
160
+ });
161
+ const config = loadedConfig ?? {};
162
162
  if (config.enableScripts === "true") {
163
163
  config.enableScripts = true;
164
164
  }
@@ -204,7 +204,7 @@ export default class CoreYarnGenerator extends Generator {
204
204
  await writeAndFormat(
205
205
  this.fs,
206
206
  ".yarnrc.yml",
207
- yml.dump(sortObject(config), {
207
+ dump(sortObject(config), {
208
208
  lineWidth: 9999,
209
209
  }),
210
210
  );
@@ -61,11 +61,7 @@ const hasData = (packages, configs) =>
61
61
  const hasTamagui = (packages, configs) =>
62
62
  packages.some(
63
63
  (pkg) =>
64
- !!(
65
- pkg.dependencies?.tamagui ||
66
- pkg.dependencies?.["@tamagui/core"] ||
67
- pkg.dependencies?.alouette
68
- ),
64
+ !!(pkg.dependencies?.tamagui || pkg.dependencies?.["@tamagui/core"]),
69
65
  );
70
66
 
71
67
  export default class PobMonorepoGenerator extends Generator {
@@ -269,9 +265,13 @@ export default class PobMonorepoGenerator extends Generator {
269
265
  `${this.pobLernaConfig.e2eTesting === "." || this.pobLernaConfig.e2eTesting === true ? "" : `/${this.pobLernaConfig.e2eTesting}`}/test-results/`,
270
266
  ].filter(Boolean);
271
267
 
272
- const gitignorePaths = [
273
- hasTamagui(this.packages, this.packageConfigs) && ".tamagui",
274
- ].filter(Boolean);
268
+ if (hasTamagui(this.packages, this.packageConfigs)) {
269
+ throw new Error(
270
+ "Tamagui is no longer supported. Please migrate to native-wind.",
271
+ );
272
+ }
273
+
274
+ const gitignorePaths = [].filter(Boolean);
275
275
 
276
276
  this.composeWith("pob:common:format-lint", {
277
277
  monorepo: true,
@@ -406,12 +406,6 @@ export default class PobMonorepoGenerator extends Generator {
406
406
  build: `${packageManagerRun(this.options.packageManager, "clean:build")} && rollup --config rollup.config.mjs`,
407
407
  watch: `${packageManagerRun(this.options.packageManager, "clean:build")} && rollup --config rollup.config.mjs --watch`,
408
408
  });
409
- packageUtils.addOrRemoveDevDependencies(
410
- pkg,
411
- rollupConfigs.length > 0 &&
412
- (rollupKinds.size === 0 || rollupKinds.has("babel")),
413
- ["@babel/core", "pob-babel"],
414
- );
415
409
 
416
410
  packageUtils.addOrRemoveDevDependencies(pkg, rollupKinds.has("esbuild"), [
417
411
  "@pob/rollup-esbuild",
@@ -1,8 +1,22 @@
1
+ import { readdirSync } from "node:fs";
1
2
  import Generator from "yeoman-generator";
3
+ import { latestLTS } from "../../../utils/nodeVersions.js";
2
4
  import * as packageUtils from "../../../utils/package.js";
3
5
  import { packageManagerRun } from "../../../utils/packageManagerUtils.js";
4
6
  import { copyAndFormatTpl } from "../../../utils/writeAndFormat.js";
5
7
 
8
+ const rootConfigExtensionsRegex = /\.config\.(?:ts|mts|cts)$/;
9
+
10
+ const hasRootConfigFiles = (rootPath) => {
11
+ try {
12
+ return readdirSync(rootPath).some((name) =>
13
+ rootConfigExtensionsRegex.test(name),
14
+ );
15
+ } catch {
16
+ return false;
17
+ }
18
+ };
19
+
6
20
  export default class MonorepoTypescriptGenerator extends Generator {
7
21
  constructor(args, opts) {
8
22
  super(args, opts);
@@ -121,15 +135,36 @@ export default class MonorepoTypescriptGenerator extends Generator {
121
135
  const tsconfigCheckPath = this.destinationPath("tsconfig.check.json");
122
136
  const tsconfigBuildPath = this.destinationPath("tsconfig.build.json");
123
137
  const tsconfigTestPath = this.destinationPath("tsconfig.test.json");
138
+ const tsconfigRootConfigsPath = this.destinationPath(
139
+ "tsconfig.root-configs.json",
140
+ );
124
141
  this.fs.delete(tsconfigTestPath);
125
142
 
126
143
  if (!this.options.enable) {
127
144
  this.fs.delete(tsconfigPath);
128
145
  this.fs.delete(tsconfigCheckPath);
129
146
  this.fs.delete(tsconfigBuildPath);
147
+ this.fs.delete(tsconfigRootConfigsPath);
130
148
  } else {
131
149
  const packagePaths = JSON.parse(this.options.packagePaths);
132
150
 
151
+ // root config files written in typescript (e.g. vitest.config.ts) are not
152
+ // part of any package tsconfig, so they need a dedicated project for
153
+ // type-aware linting and tsc -b
154
+ const hasRootConfigs = hasRootConfigFiles(this.destinationPath());
155
+ if (hasRootConfigs) {
156
+ await copyAndFormatTpl(
157
+ this.fs,
158
+ this.templatePath("tsconfig.root-configs.json.ejs"),
159
+ tsconfigRootConfigsPath,
160
+ {
161
+ nodeVersion: latestLTS,
162
+ },
163
+ );
164
+ } else {
165
+ this.fs.delete(tsconfigRootConfigsPath);
166
+ }
167
+
133
168
  await copyAndFormatTpl(
134
169
  this.fs,
135
170
  this.templatePath("tsconfig.json.ejs"),
@@ -137,6 +172,7 @@ export default class MonorepoTypescriptGenerator extends Generator {
137
172
  {
138
173
  packagePaths,
139
174
  tsConfigSuffix: false,
175
+ hasRootConfigs,
140
176
  },
141
177
  );
142
178
 
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "files": [],
3
3
  "references": [
4
+ <% if (hasRootConfigs) { -%>
5
+ { "path": "tsconfig.root-configs.json" }<%= packagePaths.length > 0 ? ',' : '' %>
6
+ <% } -%>
4
7
  <% packagePaths.forEach((packagePath, index) => { -%>
5
8
  { "path": "<%= packagePath %>/tsconfig<%= tsConfigSuffix ? `.${tsConfigSuffix}` : '' %>.json" }<%= index === packagePaths.length -1 ? '' : ',' %>
6
9
  <% }) -%>
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": [
3
+ "@pob/root/tsconfigs/strict.json",
4
+ "@pob/root/tsconfigs/targets/node-<%= nodeVersion %>.json"
5
+ ],
6
+ "include": ["*.config.ts", "*.config.mts", "*.config.cts"],
7
+ "compilerOptions": {
8
+ "noEmit": true,
9
+ "tsBuildInfoFile": "node_modules/.cache/tsc/tsbuildinfo-root-configs",
10
+ "incremental": true,
11
+ "resolveJsonModule": true
12
+ }
13
+ }
@@ -63,12 +63,15 @@ export default class MonorepoWorkspacesGenerator extends Generator {
63
63
  writing() {
64
64
  const getPackagePobConfig = (config) => ({
65
65
  babelEnvs: [],
66
+ envs: [],
66
67
  ...(config && config.pob),
67
68
  });
68
69
  const withBundler = this.packages.some((config) => {
69
70
  const pobConfig = getPackagePobConfig(config);
70
71
  return (
71
- pobConfig.babelEnvs.length > 0 || pobConfig.bundler === "rollup-babel"
72
+ pobConfig.envs.length > 0 ||
73
+ pobConfig.babelEnvs.length > 0 ||
74
+ pobConfig.bundler === "rollup-babel"
72
75
  );
73
76
  });
74
77
 
@@ -199,6 +199,10 @@ export default class PobBaseGenerator extends Generator {
199
199
 
200
200
  this.composeWith("pob:core:editorconfig");
201
201
 
202
+ this.composeWith("pob:core:claude", {
203
+ root: this.isRoot,
204
+ });
205
+
202
206
  this.composeWith("pob:core:clean", {
203
207
  root: this.isRoot,
204
208
  });
package/lib/pob.js CHANGED
@@ -24,6 +24,7 @@ import CommonTranspilerGenerator from "./generators/common/transpiler/CommonTran
24
24
  import CommonTypescriptGenerator from "./generators/common/typescript/CommonTypescriptGenerator.js";
25
25
  import CoreBunGenerator from "./generators/core/bun/CoreBunGenerator.js";
26
26
  import CoreCIGenerator from "./generators/core/ci/CoreCIGenerator.js";
27
+ import CoreClaudeGenerator from "./generators/core/claude/CoreClaudeGenerator.js";
27
28
  import CoreCleanGenerator from "./generators/core/clean/CoreCleanGenerator.js";
28
29
  import CoreEditorConfigGenerator from "./generators/core/editorconfig/CoreEditorConfigGenerator.js";
29
30
  import CoreGitGenerator from "./generators/core/git/CoreGitGenerator.js";
@@ -156,6 +157,11 @@ env.registerStub(
156
157
  "pob:core:editorconfig",
157
158
  `${__dirname}/generators/core/editorconfig/CoreEditorConfigGenerator.js`,
158
159
  );
160
+ env.registerStub(
161
+ CoreClaudeGenerator,
162
+ "pob:core:claude",
163
+ `${__dirname}/generators/core/claude/CoreClaudeGenerator.js`,
164
+ );
159
165
  env.registerStub(
160
166
  CoreGitGenerator,
161
167
  "pob:core:git",
@@ -16,32 +16,6 @@ export { default as parseAuthor } from "parse-author";
16
16
  export const parsePkgAuthor = (pkg) =>
17
17
  typeof pkg.author === "string" ? parseAuthor(pkg.author) : pkg.author;
18
18
 
19
- export const hasLerna = (pkg) =>
20
- !!(pkg.devDependencies && pkg.devDependencies.lerna);
21
-
22
- export const hasBabel = (pkg) =>
23
- !!(
24
- pkg.devDependencies &&
25
- (pkg.devDependencies["pob-babel"] || pkg.devDependencies["@babel/core"])
26
- );
27
-
28
- export const transpileWithEsbuild = (pkg) =>
29
- !!(pkg.devDependencies && pkg.devDependencies["jest-esbuild"]);
30
-
31
- export const transpileWithBabel = (pkg) =>
32
- !!(
33
- (pkg.devDependencies &&
34
- (pkg.devDependencies["pob-babel"] ||
35
- pkg.devDependencies.next ||
36
- pkg.devDependencies["@yarnpkg/builder"] ||
37
- pkg.devDependencies["alp-dev"])) ||
38
- // alp-dev has pob-babel in dependencies
39
- (pkg.dependencies &&
40
- (pkg.dependencies["pob-babel"] ||
41
- pkg.dependencies.next ||
42
- pkg.dependencies["alp-dev"]))
43
- );
44
-
45
19
  export const hasReact = (pkg) =>
46
20
  !!(
47
21
  (pkg.dependencies && pkg.dependencies.react) ||
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pob",
3
- "version": "35.6.0",
4
- "description": "Pile of bones, library generator with git/babel/typescript/typedoc/readme/jest",
3
+ "version": "36.0.0",
4
+ "description": "Pile of bones, library generator with git/babel/typescript/typedoc/readme/vitest",
5
5
  "keywords": [
6
6
  "skeleton"
7
7
  ],
@@ -28,20 +28,17 @@
28
28
  "./package.json": "./package.json"
29
29
  },
30
30
  "dependencies": {
31
- "@pob/eslint-config": "65.6.0",
32
- "@pob/eslint-config-typescript-react": "65.6.0",
33
31
  "@types/inquirer": "9.0.10",
34
32
  "@yeoman/adapter": "4.0.2",
35
- "@yeoman/types": "1.11.1",
36
- "eslint": "10.4.0",
33
+ "eslint": "10.7.0",
37
34
  "findup-sync": "^5.0.0",
38
35
  "git-remote-url": "^1.0.1",
39
36
  "github-username": "^9.0.0",
40
- "js-yaml": "^4.1.1",
37
+ "js-yaml": "^5.2.1",
41
38
  "json5": "^2.2.3",
42
39
  "lodash.camelcase": "^4.3.0",
43
40
  "lodash.kebabcase": "^4.1.1",
44
- "mem-fs": "4.1.4",
41
+ "mem-fs": "4.1.5",
45
42
  "mem-fs-editor": "12.0.4",
46
43
  "minimist": "1.2.8",
47
44
  "oxfmt": "0.54.0",
@@ -51,13 +48,16 @@
51
48
  "validate-npm-package-name": "^8.0.0",
52
49
  "yeoman-environment": "6.1.0",
53
50
  "yeoman-generator": "8.2.2",
51
+ "@pob/eslint-config": "65.7.0",
54
52
  "@pob/sort-object": "11.1.1",
55
- "@pob/sort-pkg": "13.1.1",
56
- "pob-dependencies": "24.3.0"
53
+ "@pob/sort-pkg": "13.1.2",
54
+ "pob-dependencies": "25.0.0",
55
+ "@pob/eslint-config-typescript-react": "65.7.0"
57
56
  },
58
57
  "devDependencies": {
59
58
  "@types/node": "24.13.3",
60
- "@pob/root": "24.6.0"
59
+ "@yeoman/types": "1.11.1",
60
+ "@pob/root": "25.0.0"
61
61
  },
62
62
  "engines": {
63
63
  "node": ">=22.18.0"
@@ -1,26 +0,0 @@
1
- 'use strict';
2
-
3
- module.exports = function babelConfig(api) {
4
- const isTest = api.env('test');
5
-
6
- if (!isTest) return {};
7
-
8
- return {
9
- only: [<%- only %>],
10
- presets: [
11
- ['pob-babel/preset.js', { modules: <%- jestExperimentalESM ? 'false' : "'commonjs'" %> }]
12
- <% if (hasReact) { %>, [
13
- '@babel/preset-react',
14
- {
15
- runtime: 'automatic',
16
- development: false,
17
- useBuiltIns: true,
18
- useSpread: true,
19
- },
20
- ]<% } %>
21
- <% if (hasLinaria) { %>, [
22
- '@linaria/babel-preset'
23
- ]<% } %>
24
- ],
25
- };
26
- };
@@ -1,3 +0,0 @@
1
- import { createCheckPackage } from 'check-package-dependencies';
2
-
3
- await createCheckPackage({ isLibrary: <%= isLibrary ? 'true' : 'false' %> }).checkRecommended({}).run();
@@ -1,7 +0,0 @@
1
- import { createCheckPackageWithWorkspaces } from 'check-package-dependencies';
2
-
3
- await createCheckPackageWithWorkspaces({
4
- isLibrary: () => true,
5
- })
6
- .checkRecommended()
7
- .run();