pob 38.5.0 → 38.6.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 (39) hide show
  1. package/lib/generators/app/PobAppGenerator.js +21 -3
  2. package/lib/generators/app/ignorePaths.js +4 -1
  3. package/lib/generators/common/e2e/CommonE2eGenerator.js +1 -1
  4. package/lib/generators/common/format-lint/CommonLintGenerator.js +43 -9
  5. package/lib/generators/common/format-lint/templates/oxfmtrc.jsonc.ejs +1 -1
  6. package/lib/generators/common/release/CommonReleaseGenerator.js +8 -13
  7. package/lib/generators/common/release/templates/workflow-release.yml.ejs +5 -0
  8. package/lib/generators/common/testing/CommonTestingGenerator.js +2 -2
  9. package/lib/generators/common/transpiler/CommonTranspilerGenerator.js +1 -81
  10. package/lib/generators/common/typescript/templates/tsconfig.tools.json.ejs +1 -0
  11. package/lib/generators/core/ci/CoreCIGenerator.js +1 -7
  12. package/lib/generators/core/ci/templates/github-action-documentation-workflow.yml.ejs +7 -2
  13. package/lib/generators/core/ci/templates/github-action-push-workflow-split.yml.ejs +18 -0
  14. package/lib/generators/core/ci/templates/github-action-push-workflow.yml.ejs +5 -2
  15. package/lib/generators/core/git/generators/github/CoreGitGithubGenerator.js +22 -2
  16. package/lib/generators/core/gitignore/CoreGitignoreGenerator.js +0 -8
  17. package/lib/generators/core/gitignore/templates/gitignore.ejs +6 -4
  18. package/lib/generators/core/node/CoreNodeGenerator.js +24 -0
  19. package/lib/generators/core/package/CorePackageGenerator.js +1 -17
  20. package/lib/generators/core/vscode/templates/extensions.json.ejs +1 -0
  21. package/lib/generators/core/vscode/templates/settings.json.ejs +1 -0
  22. package/lib/generators/generatedDocsOutputPath.test.js +39 -0
  23. package/lib/generators/lib/PobLibGenerator.js +31 -3
  24. package/lib/generators/lib/doc/LibDocGenerator.js +5 -2
  25. package/lib/generators/lib/doc/templates/tsconfig.doc.json.ejs +1 -1
  26. package/lib/generators/lib/doc/templates/tsconfig.doc.json.lerna.ejs +1 -1
  27. package/lib/generators/lib/readme/templates/README.md.ejs +1 -1
  28. package/lib/generators/monorepo/PobMonorepoGenerator.js +20 -6
  29. package/lib/generators/monorepo/typescript/templates/tsconfig.json.ejs +4 -4
  30. package/lib/generators/monorepo/typescript/templates/tsconfig.tools.json.ejs +1 -0
  31. package/lib/generators/monorepo/workspaces/MonorepoWorkspacesGenerator.js +2 -1
  32. package/lib/pob.js +6 -0
  33. package/lib/utils/git.js +27 -0
  34. package/lib/utils/legacyGeneratedDocs.js +26 -0
  35. package/lib/utils/legacyGeneratedDocs.test.js +58 -0
  36. package/lib/utils/nodeEngines.js +124 -0
  37. package/lib/utils/nodeEngines.test.js +168 -0
  38. package/lib/utils/packageManagerUtils.js +17 -0
  39. package/package.json +10 -9
@@ -1,7 +1,9 @@
1
1
  import { execSync } from "node:child_process";
2
2
  import { platform } from "node:process";
3
3
  import Generator from "yeoman-generator";
4
+ import { removeFromGitIndex } from "../../utils/git.js";
4
5
  import inMonorepo from "../../utils/inMonorepo.js";
6
+ import removeLegacyGeneratedDocs from "../../utils/legacyGeneratedDocs.js";
5
7
  import * as packageUtils from "../../utils/package.js";
6
8
  import { appIgnorePaths } from "./ignorePaths.js";
7
9
 
@@ -172,6 +174,7 @@ export default class PobAppGenerator extends Generator {
172
174
  }
173
175
 
174
176
  const buildDirectory = this.appConfig.distribute ? "dist" : "build";
177
+ this.buildDirectory = buildDirectory;
175
178
  const isAppLibrary =
176
179
  this.appConfig.type === "node-library" ||
177
180
  this.appConfig.type === "untranspiled-library";
@@ -332,7 +335,7 @@ export default class PobAppGenerator extends Generator {
332
335
  this.appConfig.testing &&
333
336
  pkg.name !== "yarn-plugin-conventional-version",
334
337
  enablePublish: false,
335
- withBabel: babel,
338
+ build: typescript === true && this.appConfig.type !== "expo",
336
339
  isMonorepo: false,
337
340
  ci: this.options.ci,
338
341
  disableYarnGitCache: this.options.disableYarnGitCache,
@@ -361,7 +364,6 @@ export default class PobAppGenerator extends Generator {
361
364
  testing: this.appConfig.testing,
362
365
  withBabel: babel,
363
366
  paths: ignorePaths.join("\n"),
364
- buildInGit: false,
365
367
  buildDirectory,
366
368
  });
367
369
 
@@ -395,9 +397,11 @@ export default class PobAppGenerator extends Generator {
395
397
 
396
398
  if (platform !== "win32") {
397
399
  execSync(
398
- `rm -Rf ${["lib-*", "coverage", "docs", "dist"].filter(Boolean).join(" ")}`,
400
+ `rm -Rf ${["lib-*", "coverage", "generated-docs", "dist"].filter(Boolean).join(" ")}`,
399
401
  );
400
402
  }
403
+
404
+ removeLegacyGeneratedDocs((path) => this.destinationPath(path));
401
405
  }
402
406
 
403
407
  writing() {
@@ -436,6 +440,20 @@ export default class PobAppGenerator extends Generator {
436
440
 
437
441
  this.fs.writeJSON(this.destinationPath("package.json"), pkg);
438
442
 
443
+ this.composeWith("pob:core:node", {
444
+ // only apps using pob:common:transpiler target latest LTS in engines
445
+ onlyLatestLTS:
446
+ this.appConfig.type === "node" ||
447
+ this.appConfig.type === "node-library" ||
448
+ this.appConfig.type === "alp-node",
449
+ });
439
450
  this.composeWith("pob:core:sort-package");
440
451
  }
452
+
453
+ end() {
454
+ // the build output is no longer committed: remove it from git, keeping it on disk.
455
+ if (this.buildDirectory) {
456
+ removeFromGitIndex(this.destinationPath(), this.buildDirectory);
457
+ }
458
+ }
441
459
  }
@@ -12,7 +12,10 @@ export const appIgnorePaths = {
12
12
  ].filter(Boolean),
13
13
  vite: (config) => ["/dist"],
14
14
  "vite-with-server": (config) => ["/dist"],
15
- node: (config) => (config.distribute ? [] : ["/build"]),
15
+ node: (config) => {
16
+ if (!config.distribute) return ["/build"];
17
+ return config.buildInGit ? [] : ["/dist"];
18
+ },
16
19
  "node-library": (config) => ["/build"],
17
20
  "untranspiled-library": (config) => [],
18
21
  "alp-node": (config) => ["/build"],
@@ -25,7 +25,7 @@ export default class CommonE2eGenerator extends Generator {
25
25
 
26
26
  packageUtils.addOrRemoveScripts(pkg, this.options.enable, {
27
27
  "test:e2e:prepare": "playwright install chromium",
28
- "test:e2e": "playwright test",
28
+ "test:e2e": "playwright test -c e2e/playwright.config.ts",
29
29
  });
30
30
 
31
31
  return writeAndFormatJson(
@@ -4,12 +4,27 @@ import { quoteArg } from "../../../utils/execUtils.js";
4
4
  import inMonorepo from "../../../utils/inMonorepo.js";
5
5
  import * as packageUtils from "../../../utils/package.js";
6
6
  import {
7
+ packageManagerExecWithCwd,
7
8
  packageManagerRun,
8
- packageManagerRunWithCwd,
9
9
  } from "../../../utils/packageManagerUtils.js";
10
- import { copyAndFormatTpl } from "../../../utils/writeAndFormat.js";
10
+ import {
11
+ copyAndFormatTpl,
12
+ writeAndFormatJson,
13
+ } from "../../../utils/writeAndFormat.js";
11
14
  import { appIgnorePaths } from "../../app/ignorePaths.js";
12
15
 
16
+ // same as the base ignores of @pob/eslint-config: ignorePatterns are not
17
+ // inherited through "extends"
18
+ const oxlintBaseIgnorePatterns = [
19
+ ".yarn",
20
+ "**/dist/",
21
+ "**/build/",
22
+ "**/coverage/",
23
+ "**/.next/",
24
+ "**/.tamagui/",
25
+ "**/*.d.ts",
26
+ ];
27
+
13
28
  export default class CommonFormatLintGenerator extends Generator {
14
29
  constructor(args, opts) {
15
30
  super(args, opts);
@@ -446,6 +461,8 @@ export default class CommonFormatLintGenerator extends Generator {
446
461
  );
447
462
  this.fs.delete(invalidEslintConfigPath);
448
463
 
464
+ const oxlintConfigPath = this.destinationPath(".oxlintrc.json");
465
+
449
466
  if (!inMonorepo || inMonorepo.root) {
450
467
  const rootIgnorePaths = this.options.rootIgnorePaths
451
468
  .split("\n")
@@ -453,12 +470,8 @@ export default class CommonFormatLintGenerator extends Generator {
453
470
  const getRootIgnorePatterns = () => {
454
471
  const ignorePatterns = new Set();
455
472
 
456
- if (useTypescript) {
457
- ignorePatterns.add("*.d.ts");
458
- }
459
-
460
473
  if (inMonorepo && inMonorepo.root && this.options.documentation) {
461
- ignorePatterns.add("/docs");
474
+ ignorePatterns.add("/generated-docs");
462
475
  }
463
476
 
464
477
  if ((!inMonorepo || !inMonorepo.root) && useTypescript) {
@@ -514,8 +527,26 @@ export default class CommonFormatLintGenerator extends Generator {
514
527
  },
515
528
  */
516
529
  }
530
+
531
+ // keeps existing options, only enforces the shared config and ignores.
532
+ // ignorePatterns are fully owned by the generator: merging with existing
533
+ // ones would never remove stale patterns
534
+ const oxlintConfig = this.fs.readJSON(oxlintConfigPath, {});
535
+ await writeAndFormatJson(this.fs, oxlintConfigPath, {
536
+ ...oxlintConfig,
537
+ extends: [
538
+ "./node_modules/@pob/eslint-config/oxlint/base.json",
539
+ ...(oxlintConfig.extends || []).filter(
540
+ (value) => !value.includes("@pob/eslint-config/"),
541
+ ),
542
+ ],
543
+ ignorePatterns: [
544
+ ...new Set([...oxlintBaseIgnorePatterns, ...ignorePatterns]),
545
+ ],
546
+ });
517
547
  } else {
518
548
  this.fs.delete(eslintConfigPath);
549
+ this.fs.delete(oxlintConfigPath);
519
550
  }
520
551
 
521
552
  // see monorepo/lerna/index.js
@@ -524,9 +555,12 @@ export default class CommonFormatLintGenerator extends Generator {
524
555
 
525
556
  packageUtils.addScripts(pkg, {
526
557
  "lint:eslint": globalEslint
527
- ? `${packageManagerRunWithCwd(this.options.packageManager, "../..", "eslint")} ${args} ${quoteArg(path.relative("../..", "."))}`
558
+ ? `${packageManagerExecWithCwd(this.options.packageManager, "../..", "eslint")} ${args} ${quoteArg(path.relative("../..", "."))}`
528
559
  : `eslint ${args} .`,
529
- lint: `${
560
+ "lint:oxlint": globalEslint
561
+ ? `${packageManagerExecWithCwd(this.options.packageManager, "../..", "oxlint")} ${quoteArg(path.relative("../..", "."))}`
562
+ : "oxlint",
563
+ lint: `${packageManagerRun(this.options.packageManager, "lint:oxlint")} && ${
530
564
  useTypescript && !composite ? "tsc && " : ""
531
565
  }${packageManagerRun(this.options.packageManager, "lint:eslint")}`,
532
566
  });
@@ -4,7 +4,7 @@
4
4
  "sortPackageJson": { "sortScripts": true },
5
5
  "ignorePatterns": [
6
6
  <% if (documentation) { -%>
7
- "/docs",
7
+ "/generated-docs",
8
8
  <% } -%>
9
9
  <% if (packageManager === 'yarn' && inRoot) { -%>
10
10
  "/.yarnrc.yml",
@@ -23,19 +23,13 @@ export default class CommonReleaseGenerator extends Generator {
23
23
  description: "If publish on npm is enabled",
24
24
  });
25
25
 
26
- this.option("withBabel", {
26
+ this.option("build", {
27
27
  type: Boolean,
28
- required: false,
29
- default: undefined,
30
- description: "Babel enabled.",
28
+ required: true,
29
+ description:
30
+ "If there is a build script. The build output is not necessarily committed, it must be built before publishing.",
31
31
  });
32
32
 
33
- this.option("withTypescript", {
34
- type: Boolean,
35
- required: false,
36
- default: undefined,
37
- description: "Typescript enabled.",
38
- });
39
33
  this.option("isMonorepo", {
40
34
  type: Boolean,
41
35
  default: false,
@@ -82,6 +76,7 @@ export default class CommonReleaseGenerator extends Generator {
82
76
  {
83
77
  packageManager: this.options.packageManager,
84
78
  enablePublish: this.options.enablePublish,
79
+ build: this.options.build,
85
80
  disableYarnGitCache: this.options.disableYarnGitCache,
86
81
  isMonorepo: this.options.isMonorepo,
87
82
  isMonorepoIndependent:
@@ -89,6 +84,7 @@ export default class CommonReleaseGenerator extends Generator {
89
84
  (!pkg.version || pkg.version === "0.0.0"),
90
85
  nodeLatestMajorVersion: latestLTS,
91
86
  packageManagerExec,
87
+ packageManagerRun,
92
88
  },
93
89
  );
94
90
  } else {
@@ -110,9 +106,8 @@ export default class CommonReleaseGenerator extends Generator {
110
106
  packageUtils.addScripts(pkg, {
111
107
  preversion: [
112
108
  packageManagerRun(this.options.packageManager, "lint"),
113
- this.options.withBabel ||
114
- (this.options.withTypescript &&
115
- packageManagerRun(this.options.packageManager, "build")),
109
+ this.options.build &&
110
+ packageManagerRun(this.options.packageManager, "build"),
116
111
  "repository-check-dirty",
117
112
  ]
118
113
  .filter(Boolean)
@@ -83,6 +83,11 @@ jobs:
83
83
  - name: Install Dependencies
84
84
  run: pnpm install --frozen-lockfile
85
85
  <% } -%>
86
+ <% if (build) { -%>
87
+
88
+ - name: Build
89
+ run: <%= packageManagerRun(packageManager, 'build') %>
90
+ <% } -%>
86
91
 
87
92
  - name: New version (dry run)
88
93
  if: github.ref == 'refs/heads/main' && inputs.dry-run
@@ -267,7 +267,7 @@ export default class CommonTestingGenerator extends Generator {
267
267
  const experimentalTestCoverage = true;
268
268
  return [
269
269
  experimentalTestCoverage && coverage === "generate"
270
- ? "mkdir -p docs && "
270
+ ? "mkdir -p generated-docs && "
271
271
  : "",
272
272
  `TZ=UTC ${
273
273
  coverage && !experimentalTestCoverage
@@ -281,7 +281,7 @@ export default class CommonTestingGenerator extends Generator {
281
281
  this.options.typescript
282
282
  ? `${tsTestLoaderOption ? `${tsTestLoaderOption} ` : ""}`
283
283
  : ""
284
- }${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}/*/` : ""}${`${
284
+ }${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=generated-docs/coverage.lcov" : ""} --test-coverage-include="${this.options.srcDirectory}/**/*.ts"` : ""} '${this.options.monorepo ? `${workspacesPattern}/*/` : ""}${`${
285
285
  hasTestFolder
286
286
  ? "test/*"
287
287
  : `${this.options.srcDirectory}/**/*.test`
@@ -1,5 +1,4 @@
1
1
  import fs from "node:fs";
2
- import semver from "semver";
3
2
  import Generator from "yeoman-generator";
4
3
  import { latestLTS, maintenanceLTS } from "../../../utils/nodeVersions.js";
5
4
  import * as packageUtils from "../../../utils/package.js";
@@ -285,9 +284,6 @@ export default class CommonTranspilerGenerator extends Generator {
285
284
  ["alp-rollup-plugin-config"],
286
285
  );
287
286
 
288
- /* engines */
289
- // TODO move from CommonBabelGenerator
290
-
291
287
  /* side effects */
292
288
 
293
289
  if (this.options.isApp && !this.options.isAppLibrary) {
@@ -660,86 +656,10 @@ export default class CommonTranspilerGenerator extends Generator {
660
656
  const entries = pkg.pob.entries || ["index"];
661
657
  const envs = pkg.pob.envs || pkg.pob.babelEnvs;
662
658
 
663
- const hasTargetNode = envs && envs.some((env) => env.target === "node");
664
659
  const hasTargetBrowser =
665
660
  envs && envs.some((env) => env.target === "browser");
666
661
 
667
- if (!pkg.engines) pkg.engines = {};
668
-
669
- if (hasTargetNode || !envs) {
670
- const minNodeVersion = envs
671
- ? Math.min(
672
- ...envs
673
- .filter((env) => env.target === "node")
674
- .map((env) => env.version),
675
- )
676
- : (() =>
677
- this.options.onlyLatestLTS
678
- ? `${latestLTS}`
679
- : `${maintenanceLTS}`)();
680
-
681
- switch (String(minNodeVersion)) {
682
- case "4":
683
- case "6":
684
- case "8":
685
- case "10":
686
- case "12":
687
- case "14":
688
- case "16":
689
- case "18":
690
- case "20":
691
- case "22":
692
- if (
693
- envs ||
694
- !pkg.engines.node ||
695
- !pkg.engines.node.startsWith(">=24")
696
- ) {
697
- pkg.engines.node = ">=22.18.0";
698
- }
699
- break;
700
- case "24":
701
- if (
702
- envs ||
703
- !pkg.engines.node ||
704
- !pkg.engines.node.startsWith(">=26")
705
- ) {
706
- pkg.engines.node = ">=24.14.1";
707
- }
708
- break;
709
- case "26":
710
- pkg.engines.node = ">=26.0.0";
711
- break;
712
- default:
713
- throw new Error(`Invalid min node version: ${minNodeVersion}`);
714
- }
715
-
716
- if (pkg.dependencies && pkg.dependencies["@types/node"]) {
717
- pkg.dependencies["@types/node"] = `>=${minNodeVersion}.0.0`;
718
- }
719
- if (
720
- pkg.devDependencies &&
721
- pkg.devDependencies["@types/node"] &&
722
- !semver.satisfies(
723
- pkg.devDependencies["@types/node"],
724
- `>=${minNodeVersion}.0.0`,
725
- )
726
- ) {
727
- pkg.devDependencies["@types/node"] = `>=${minNodeVersion}.0.0`;
728
- }
729
- } else {
730
- packageUtils.removeDependencies(pkg, ["@types/node"]);
731
- packageUtils.removeDevDependencies(pkg, ["@types/node"]);
732
-
733
- // Supports oldest current or active LTS version of node
734
- const minVersion = this.options.onlyLatestLTS ? "24.14.1" : "22.18.0";
735
-
736
- if (
737
- !pkg.engines.node ||
738
- semver.lt(semver.minVersion(pkg.engines.node), minVersion)
739
- ) {
740
- pkg.engines.node = `>=${minVersion}`;
741
- }
742
- }
662
+ // engines.node and @types/node are handled by pob:core:node
743
663
 
744
664
  this.fs.delete("rollup.config.js");
745
665
  if (
@@ -8,6 +8,7 @@
8
8
  "scripts/**/*.ts",
9
9
  "scripts/**/*.mts",
10
10
  "scripts/**/*.cts",
11
+ "*.config.js",
11
12
  "*.config.ts",
12
13
  "*.config.mts",
13
14
  "*.config.cts"
@@ -200,16 +200,10 @@ export default class CoreCIGenerator extends Generator {
200
200
  this.destinationPath(".github/workflows/gh-pages.yml"),
201
201
  {
202
202
  packageManager: this.options.packageManager,
203
- packageManagerRun: (script, packagePath) => {
204
- return packageManagerRun(
205
- this.options.packageManager,
206
- "docs:build",
207
- packagePath,
208
- );
209
- },
210
203
  disableYarnGitCache: this.options.disableYarnGitCache,
211
204
  testing: this.options.testing,
212
205
  testRunner: this.options.testRunner,
206
+ build: this.options.build,
213
207
  typedoc: this.options.documentation && this.options.typescript,
214
208
  nodeLatestMajorVersion: latestLTS,
215
209
  },
@@ -45,6 +45,11 @@ jobs:
45
45
  - name: Install Dependencies
46
46
  run: pnpm install --frozen-lockfile
47
47
  <% } -%>
48
+ <% if (build) { -%>
49
+
50
+ - name: Build
51
+ run: <%= packageManager %> run build
52
+ <% } -%>
48
53
 
49
54
  <% if (typedoc) { -%>
50
55
  - name: Run tsc for tsc cache
@@ -55,10 +60,10 @@ jobs:
55
60
  <% } -%>
56
61
 
57
62
  - name: Create nojekyll
58
- run: touch docs/.nojekyll
63
+ run: touch generated-docs/.nojekyll
59
64
 
60
65
  - name: Deploy
61
66
  uses: peaceiris/actions-gh-pages@v4
62
67
  with:
63
68
  github_token: ${{ secrets.GITHUB_TOKEN }}
64
- publish_dir: ./docs
69
+ publish_dir: ./generated-docs
@@ -138,6 +138,11 @@ jobs:
138
138
  <% } else { -%>
139
139
  run: npm ci
140
140
  <% } -%>
141
+ <% if (build) { -%>
142
+
143
+ - name: Build
144
+ run: <%= packageManagerRun("build") %>
145
+ <% } -%>
141
146
 
142
147
  - name: Format
143
148
  run: <%= packageManagerRun("format:check") %>
@@ -147,6 +152,9 @@ jobs:
147
152
  run: <%= packageManagerRun("tsc") %>
148
153
  <% } -%>
149
154
 
155
+ - name: Oxlint
156
+ run: <%= packageManagerRun("lint:oxlint") %>
157
+
150
158
  - name: Eslint
151
159
  run: <%= packageManagerRun("lint:eslint") %>
152
160
  <% if (testing) { -%>
@@ -196,6 +204,11 @@ jobs:
196
204
  - name: Install Dependencies
197
205
  run: pnpm install --frozen-lockfile
198
206
  <% } -%>
207
+ <% if (build) { -%>
208
+
209
+ - name: Build
210
+ run: <%= packageManagerRun("build") %>
211
+ <% } -%>
199
212
 
200
213
  <% if (codecov) { -%>
201
214
  - name: Test
@@ -267,6 +280,11 @@ jobs:
267
280
  <% } else { -%>
268
281
  run: npm ci
269
282
  <% } -%>
283
+ <% if (build) { -%>
284
+
285
+ - name: Build
286
+ run: <%= packageManagerRun("build") %>
287
+ <% } -%>
270
288
 
271
289
  - name: E2E testing
272
290
  run: <%= packageManagerRun("test:e2e", e2eTesting) %>
@@ -64,7 +64,6 @@ jobs:
64
64
  <% if (build) { -%>
65
65
  - name: Build
66
66
  run: <%= packageManager %> run build
67
- if: startsWith(matrix.node-version, '<%= nodeLatestMajorVersion %>.')
68
67
 
69
68
  <% } -%>
70
69
  - name: Format
@@ -77,6 +76,10 @@ jobs:
77
76
  if: startsWith(matrix.node-version, '<%= nodeLatestMajorVersion %>.')
78
77
  <% } -%>
79
78
 
79
+ - name: Oxlint
80
+ run: <%= packageManager %> run lint:oxlint
81
+ if: startsWith(matrix.node-version, '<%= nodeLatestMajorVersion %>.')
82
+
80
83
  - name: Eslint
81
84
  run: <%= packageManager %> run lint:eslint
82
85
  if: startsWith(matrix.node-version, '<%= nodeLatestMajorVersion %>.')
@@ -99,7 +102,7 @@ jobs:
99
102
  with:
100
103
  fail_ci_if_error: true
101
104
  token: ${{ secrets.CODECOV_TOKEN }}
102
- files: ./docs/coverage.lcov
105
+ files: ./generated-docs/coverage.lcov
103
106
  disable_search: true
104
107
  if: startsWith(matrix.node-version, '<%= nodeLatestMajorVersion %>.') && github.actor != 'dependabot[bot]'
105
108
  <% } else if (testing) { -%>
@@ -1,10 +1,30 @@
1
1
  /* eslint-disable camelcase */
2
2
 
3
+ import { spawnSync } from "node:child_process";
4
+ import * as os from "node:os";
3
5
  import Generator from "yeoman-generator";
4
6
  import { ciContexts } from "../../../ci/CoreCIGenerator.js";
5
7
  // const packageUtils = require('../../../../../utils/package');
6
8
 
7
- const GITHUB_TOKEN = process.env.POB_GITHUB_TOKEN;
9
+ const readTokenFromKeychain = () => {
10
+ if (process.platform !== "darwin") return undefined;
11
+ const result = spawnSync(
12
+ "security",
13
+ [
14
+ "find-generic-password",
15
+ "-s",
16
+ "pob-github-token",
17
+ "-a",
18
+ os.userInfo().username,
19
+ "-w",
20
+ ],
21
+ { encoding: "utf8" },
22
+ );
23
+ if (result.status !== 0) return undefined;
24
+ return result.stdout.trim() || undefined;
25
+ };
26
+
27
+ const GITHUB_TOKEN = process.env.POB_GITHUB_TOKEN || readTokenFromKeychain();
8
28
 
9
29
  const postJson = (url, jsonBody) =>
10
30
  fetch(`https://api.github.com/${url}`, {
@@ -121,7 +141,7 @@ export default class CoreGitGithubGenerator extends Generator {
121
141
 
122
142
  if (!GITHUB_TOKEN && process.env.CI !== "true") {
123
143
  console.warn(
124
- "Missing POB_GITHUB_TOKEN. Create one with https://github.com/settings/tokens/new?scopes=repo&description=POB%20Generator and add it in your env variables.",
144
+ 'Missing POB_GITHUB_TOKEN. Create one with https://github.com/settings/tokens/new?scopes=repo&description=POB%20Generator and add it in your env variables, or store it in the macOS keychain with: security add-generic-password -s pob-github-token -a "$USER" -w',
125
145
  );
126
146
  }
127
147
  }
@@ -46,13 +46,6 @@ export default class CoreGitignoreGenerator extends Generator {
46
46
  description: "Typescript use.",
47
47
  });
48
48
 
49
- this.option("buildInGit", {
50
- type: Boolean,
51
- required: false,
52
- default: true,
53
- description: "Build is saved in git.",
54
- });
55
-
56
49
  this.option("buildDirectory", {
57
50
  type: String,
58
51
  required: false,
@@ -88,7 +81,6 @@ export default class CoreGitignoreGenerator extends Generator {
88
81
  withBabel,
89
82
  typescript: withBabel || this.options.typescript,
90
83
  paths: this.options.paths,
91
- buildInGit: this.options.buildInGit,
92
84
  playwright: this.options.playwright,
93
85
  });
94
86
  }
@@ -8,7 +8,9 @@ yarn-debug.log*
8
8
  yarn-error.log*
9
9
  <% } -%>
10
10
  <% if (paths) { -%>
11
+ <% if (root) { -%>
11
12
 
13
+ <% } -%>
12
14
  <%= paths %>
13
15
  <% } -%>
14
16
  <% if (root) { -%>
@@ -20,17 +22,17 @@ yarn-error.log*
20
22
  !/.vscode
21
23
  *.sublime-project
22
24
  *.sublime-workspace
23
- <% if (documentation) { -%>
25
+ <% if (documentation || testing) { -%>
24
26
 
25
- # generated documentation directory
26
- /docs
27
+ # generated documentation and coverage output
28
+ /generated-docs
27
29
  <% } -%>
28
30
  <% if (testing) { -%>
29
31
 
30
32
  # default coverage directory
31
33
  /coverage
32
34
  <% } -%>
33
- <% if (typescript && buildInGit) { -%>
35
+ <% if (typescript) { -%>
34
36
 
35
37
  # Typescript
36
38
  *.tsbuildinfo
@@ -0,0 +1,24 @@
1
+ import Generator from "yeoman-generator";
2
+ import { updateNodeEngines } from "../../../utils/nodeEngines.js";
3
+
4
+ export default class CoreNodeGenerator extends Generator {
5
+ constructor(args, opts) {
6
+ super(args, opts);
7
+
8
+ this.option("onlyLatestLTS", {
9
+ type: Boolean,
10
+ required: false,
11
+ default: false,
12
+ description: "only support latest LTS version of node",
13
+ });
14
+ }
15
+
16
+ writing() {
17
+ const pkg = this.fs.readJSON(this.destinationPath("package.json"));
18
+
19
+ updateNodeEngines(pkg, { onlyLatestLTS: this.options.onlyLatestLTS });
20
+
21
+ // no formatting needed, pob:core:sort-package runs after and formats
22
+ this.fs.writeJSON(this.destinationPath("package.json"), pkg);
23
+ }
24
+ }
@@ -53,23 +53,7 @@ export default class CorePackageGenerator extends Generator {
53
53
  async initializing() {
54
54
  const pkg = this.fs.readJSON(this.destinationPath("package.json"), {});
55
55
 
56
- if (!pkg.engines) pkg.engines = {};
57
-
58
- // dont override engines if set to latest
59
- if (
60
- !pkg.engines.node ||
61
- !(
62
- pkg.engines.node.startsWith(">=22.") ||
63
- pkg.engines.node.startsWith(">=24.")
64
- )
65
- ) {
66
- // this might be overridden by babel generator
67
- pkg.engines.node = ">=22.18.0"; // 22.18.0 is the version with strip typescript out of experimental status
68
- }
69
-
70
- if (pkg.engines.node.startsWith(">=22.11.")) {
71
- pkg.engines.node = ">=22.18.0";
72
- }
56
+ // engines.node is handled by pob:core:node
73
57
 
74
58
  if (!this.options.isRoot) {
75
59
  delete pkg.packageManager;
@@ -6,6 +6,7 @@
6
6
  <% if (yarn && pnp) { -%>
7
7
  "arcanis.vscode-zipfs",
8
8
  <% } -%>
9
+ "oxc.oxc-vscode",
9
10
  "dbaeumer.vscode-eslint",
10
11
  "EditorConfig.EditorConfig",
11
12
  "esbenp.prettier-vscode"<% if (typescript) { -%>,