pob 38.4.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.
- package/lib/generators/app/PobAppGenerator.js +21 -3
- package/lib/generators/app/ignorePaths.js +4 -1
- package/lib/generators/common/e2e/CommonE2eGenerator.js +1 -1
- package/lib/generators/common/format-lint/CommonLintGenerator.js +43 -9
- package/lib/generators/common/format-lint/templates/oxfmtrc.jsonc.ejs +1 -1
- package/lib/generators/common/release/CommonReleaseGenerator.js +8 -13
- package/lib/generators/common/release/templates/workflow-release.yml.ejs +5 -0
- package/lib/generators/common/testing/CommonTestingGenerator.js +2 -2
- package/lib/generators/common/transpiler/CommonTranspilerGenerator.js +1 -81
- package/lib/generators/common/typescript/templates/tsconfig.tools.json.ejs +1 -0
- package/lib/generators/core/ci/CoreCIGenerator.js +1 -7
- package/lib/generators/core/ci/templates/github-action-documentation-workflow.yml.ejs +7 -2
- package/lib/generators/core/ci/templates/github-action-push-workflow-split.yml.ejs +18 -0
- package/lib/generators/core/ci/templates/github-action-push-workflow.yml.ejs +5 -2
- package/lib/generators/core/git/generators/github/CoreGitGithubGenerator.js +22 -2
- package/lib/generators/core/gitignore/CoreGitignoreGenerator.js +0 -8
- package/lib/generators/core/gitignore/templates/gitignore.ejs +6 -4
- package/lib/generators/core/node/CoreNodeGenerator.js +24 -0
- package/lib/generators/core/package/CorePackageGenerator.js +1 -17
- package/lib/generators/core/vscode/templates/extensions.json.ejs +1 -0
- package/lib/generators/core/vscode/templates/settings.json.ejs +1 -0
- package/lib/generators/generatedDocsOutputPath.test.js +39 -0
- package/lib/generators/lib/PobLibGenerator.js +31 -3
- package/lib/generators/lib/doc/LibDocGenerator.js +5 -2
- package/lib/generators/lib/doc/templates/tsconfig.doc.json.ejs +1 -1
- package/lib/generators/lib/doc/templates/tsconfig.doc.json.lerna.ejs +1 -1
- package/lib/generators/lib/readme/templates/README.md.ejs +1 -1
- package/lib/generators/monorepo/PobMonorepoGenerator.js +20 -6
- package/lib/generators/monorepo/typescript/templates/tsconfig.json.ejs +4 -4
- package/lib/generators/monorepo/typescript/templates/tsconfig.tools.json.ejs +5 -1
- package/lib/generators/monorepo/workspaces/MonorepoWorkspacesGenerator.js +2 -1
- package/lib/pob.js +6 -0
- package/lib/utils/git.js +27 -0
- package/lib/utils/legacyGeneratedDocs.js +26 -0
- package/lib/utils/legacyGeneratedDocs.test.js +58 -0
- package/lib/utils/nodeEngines.js +124 -0
- package/lib/utils/nodeEngines.test.js +168 -0
- package/lib/utils/packageManagerUtils.js +17 -0
- package/package.json +11 -10
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
|
|
5
|
+
const generatorsDir = import.meta.dirname;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The "docs" directory is reserved for hand written documentation in generated
|
|
9
|
+
* projects. Generated output (typedoc, coverage lcov, gh-pages publish dir)
|
|
10
|
+
* lives in "generated-docs". This matches a bare "docs" path segment, while
|
|
11
|
+
* allowing "generated-docs", "generate:docs" and urls like
|
|
12
|
+
* "docs.renovatebot.com".
|
|
13
|
+
*/
|
|
14
|
+
const legacyDocsPath = /(?<![\w.:-])docs(?![\w.-])/;
|
|
15
|
+
|
|
16
|
+
describe("generated documentation output path", () => {
|
|
17
|
+
it("never targets the reserved directory", async () => {
|
|
18
|
+
const entries = await fs.readdir(generatorsDir, {
|
|
19
|
+
recursive: true,
|
|
20
|
+
withFileTypes: true,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const offenders = [];
|
|
24
|
+
for (const entry of entries) {
|
|
25
|
+
if (!entry.isFile() || entry.name.endsWith(".test.js")) continue;
|
|
26
|
+
const filePath = path.join(entry.parentPath, entry.name);
|
|
27
|
+
const content = await fs.readFile(filePath, "utf8");
|
|
28
|
+
content.split("\n").forEach((line, index) => {
|
|
29
|
+
if (legacyDocsPath.test(line)) {
|
|
30
|
+
offenders.push(
|
|
31
|
+
`${path.relative(generatorsDir, filePath)}:${index + 1}: ${line.trim()}`,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
expect(offenders).toEqual([]);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { rmSync } from "node:fs";
|
|
2
2
|
import Generator from "yeoman-generator";
|
|
3
|
+
import { removeFromGitIndex } from "../../utils/git.js";
|
|
3
4
|
import inMonorepo from "../../utils/inMonorepo.js";
|
|
5
|
+
import removeLegacyGeneratedDocs from "../../utils/legacyGeneratedDocs.js";
|
|
4
6
|
import { latestLTS } from "../../utils/nodeVersions.js";
|
|
5
7
|
import * as packageUtils from "../../utils/package.js";
|
|
6
8
|
|
|
@@ -254,6 +256,17 @@ export default class PobLibGenerator extends Generator {
|
|
|
254
256
|
this.pobjson.e2e = e2e;
|
|
255
257
|
}
|
|
256
258
|
|
|
259
|
+
// build in git
|
|
260
|
+
if (!this.updateOnly) {
|
|
261
|
+
const { buildInGit } = await this.prompt({
|
|
262
|
+
type: "confirm",
|
|
263
|
+
name: "buildInGit",
|
|
264
|
+
message: "Would you like the build output committed in git ?",
|
|
265
|
+
default: this.pobjson.buildInGit === true,
|
|
266
|
+
});
|
|
267
|
+
this.pobjson.buildInGit = buildInGit;
|
|
268
|
+
}
|
|
269
|
+
|
|
257
270
|
this.fs.writeJSON(this.destinationPath("package.json"), pkg);
|
|
258
271
|
|
|
259
272
|
this.composeWith("pob:common:babel", {
|
|
@@ -378,8 +391,7 @@ export default class PobLibGenerator extends Generator {
|
|
|
378
391
|
enable: !inMonorepo && this.pobjson.testing,
|
|
379
392
|
packageManager,
|
|
380
393
|
enablePublish: true,
|
|
381
|
-
withBabel,
|
|
382
|
-
withTypescript,
|
|
394
|
+
build: withBabel || withTypescript,
|
|
383
395
|
isMonorepo: false,
|
|
384
396
|
ci: this.options.ci,
|
|
385
397
|
disableYarnGitCache: this.options.disableYarnGitCache,
|
|
@@ -397,6 +409,9 @@ export default class PobLibGenerator extends Generator {
|
|
|
397
409
|
});
|
|
398
410
|
|
|
399
411
|
const buildDirectory = withBabel || withTypescript ? "dist" : "";
|
|
412
|
+
const buildInGit = this.pobjson.buildInGit === true;
|
|
413
|
+
this.buildDirectory = buildDirectory;
|
|
414
|
+
this.buildInGit = buildInGit;
|
|
400
415
|
|
|
401
416
|
// must be after doc, testing
|
|
402
417
|
this.composeWith("pob:core:gitignore", {
|
|
@@ -405,6 +420,7 @@ export default class PobLibGenerator extends Generator {
|
|
|
405
420
|
typescript: withTypescript,
|
|
406
421
|
documentation: this.pobjson.documentation,
|
|
407
422
|
testing: !!this.pobjson.testing,
|
|
423
|
+
paths: !buildInGit && buildDirectory ? `/${buildDirectory}` : "",
|
|
408
424
|
buildDirectory,
|
|
409
425
|
playwright: this.pobjson.e2e,
|
|
410
426
|
});
|
|
@@ -464,7 +480,7 @@ export default class PobLibGenerator extends Generator {
|
|
|
464
480
|
"lib-node14",
|
|
465
481
|
"lib-node16",
|
|
466
482
|
"coverage",
|
|
467
|
-
this.pobjson.documentation && "docs",
|
|
483
|
+
this.pobjson.documentation && "generated-docs",
|
|
468
484
|
!(withBabel || withTypescript) && "dist",
|
|
469
485
|
]
|
|
470
486
|
.filter(Boolean)
|
|
@@ -472,11 +488,23 @@ export default class PobLibGenerator extends Generator {
|
|
|
472
488
|
rmSync(path, { recursive: true, force: true });
|
|
473
489
|
});
|
|
474
490
|
|
|
491
|
+
removeLegacyGeneratedDocs((path) => this.destinationPath(path));
|
|
492
|
+
|
|
475
493
|
const { pobjson } = this;
|
|
476
494
|
|
|
477
495
|
this.config.set("lib", pobjson);
|
|
478
496
|
this.config.save();
|
|
479
497
|
|
|
498
|
+
this.composeWith("pob:core:node", {
|
|
499
|
+
onlyLatestLTS: this.onlyLatestLTS,
|
|
500
|
+
});
|
|
480
501
|
this.composeWith("pob:core:sort-package");
|
|
481
502
|
}
|
|
503
|
+
|
|
504
|
+
end() {
|
|
505
|
+
// the build output is no longer committed: remove it from git, keeping it on disk.
|
|
506
|
+
if (!this.buildInGit && this.buildDirectory) {
|
|
507
|
+
removeFromGitIndex(this.destinationPath(), this.buildDirectory);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
482
510
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Generator from "yeoman-generator";
|
|
2
2
|
import inMonorepo from "../../../utils/inMonorepo.js";
|
|
3
|
+
import removeLegacyGeneratedDocs from "../../../utils/legacyGeneratedDocs.js";
|
|
3
4
|
import * as packageUtils from "../../../utils/package.js";
|
|
4
5
|
import { copyAndFormatTpl } from "../../../utils/writeAndFormat.js";
|
|
5
6
|
|
|
@@ -35,6 +36,8 @@ export default class LibDocGenerator extends Generator {
|
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
async writing() {
|
|
39
|
+
removeLegacyGeneratedDocs((path) => this.destinationPath(path));
|
|
40
|
+
|
|
38
41
|
if (this.fs.exists(this.destinationPath("jsdoc.conf.json"))) {
|
|
39
42
|
this.fs.delete(this.destinationPath("jsdoc.conf.json"));
|
|
40
43
|
}
|
|
@@ -112,8 +115,8 @@ export default class LibDocGenerator extends Generator {
|
|
|
112
115
|
}
|
|
113
116
|
} else {
|
|
114
117
|
// this.fs.delete(this.destinationPath('jsdoc.conf.js'));
|
|
115
|
-
if (this.fs.exists(this.destinationPath("docs"))) {
|
|
116
|
-
this.fs.delete(this.destinationPath("docs"));
|
|
118
|
+
if (this.fs.exists(this.destinationPath("generated-docs"))) {
|
|
119
|
+
this.fs.delete(this.destinationPath("generated-docs"));
|
|
117
120
|
}
|
|
118
121
|
|
|
119
122
|
if (this.fs.exists(this.destinationPath("tsconfig.doc.json"))) {
|
|
@@ -36,7 +36,7 @@ npm install --save <%= packageName %>
|
|
|
36
36
|
<% if (documentation && ci && gitHost === 'github') { -%>
|
|
37
37
|
## API
|
|
38
38
|
|
|
39
|
-
[https://<%= gitAccount %>.github.io/<%= packageName %>/
|
|
39
|
+
[https://<%= gitAccount %>.github.io/<%= packageName %>/](https://<%= gitAccount %>.github.io/<%= packageName %>/)
|
|
40
40
|
|
|
41
41
|
<% } -%>
|
|
42
42
|
## Usage
|
|
@@ -2,6 +2,7 @@ import { execSync } from "node:child_process";
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import { platform } from "node:process";
|
|
4
4
|
import Generator from "yeoman-generator";
|
|
5
|
+
import removeLegacyGeneratedDocs from "../../utils/legacyGeneratedDocs.js";
|
|
5
6
|
import * as packageUtils from "../../utils/package.js";
|
|
6
7
|
import { packageManagerRun } from "../../utils/packageManagerUtils.js";
|
|
7
8
|
import {
|
|
@@ -160,7 +161,7 @@ export default class PobMonorepoGenerator extends Generator {
|
|
|
160
161
|
return;
|
|
161
162
|
}
|
|
162
163
|
|
|
163
|
-
if (this.pobMonorepoConfig
|
|
164
|
+
if (this.pobMonorepoConfig?.ciPushWorkflow) {
|
|
164
165
|
throw new Error(
|
|
165
166
|
"ciPushWorkflow is deprecated, use disablePushWorkflow instead",
|
|
166
167
|
);
|
|
@@ -181,7 +182,7 @@ export default class PobMonorepoGenerator extends Generator {
|
|
|
181
182
|
name: "disablePushWorkflow",
|
|
182
183
|
message: "Would you like to DISABLE push workflow ?",
|
|
183
184
|
when: (answers) => answers.ci,
|
|
184
|
-
default: config
|
|
185
|
+
default: config?.disablePushWorkflow,
|
|
185
186
|
},
|
|
186
187
|
{
|
|
187
188
|
type: "confirm",
|
|
@@ -256,6 +257,14 @@ export default class PobMonorepoGenerator extends Generator {
|
|
|
256
257
|
|
|
257
258
|
const splitCIJobs = this.packageNames.length > 8;
|
|
258
259
|
|
|
260
|
+
// the root has a build script when there are typescript definitions or rollup
|
|
261
|
+
// configs to build. The build output is not necessarily committed, so it must be
|
|
262
|
+
// built in ci and before publishing.
|
|
263
|
+
const hasRootBuild =
|
|
264
|
+
this.pobMonorepoConfig.typescript === true ||
|
|
265
|
+
(!this.options.isAppProject &&
|
|
266
|
+
this.packages.some((pkg) => pkg.pob?.bundler));
|
|
267
|
+
|
|
259
268
|
this.composeWith("pob:common:testing", {
|
|
260
269
|
monorepo: true,
|
|
261
270
|
enable: this.pobMonorepoConfig.testing,
|
|
@@ -263,7 +272,7 @@ export default class PobMonorepoGenerator extends Generator {
|
|
|
263
272
|
disableYarnGitCache: this.options.disableYarnGitCache,
|
|
264
273
|
testing: this.pobMonorepoConfig.testing,
|
|
265
274
|
e2eTesting: this.pobMonorepoConfig.e2eTesting,
|
|
266
|
-
build:
|
|
275
|
+
build: hasRootBuild,
|
|
267
276
|
typescript: this.pobMonorepoConfig.typescript,
|
|
268
277
|
documentation: !!this.pobMonorepoConfig.documentation,
|
|
269
278
|
codecov: this.pobMonorepoConfig.testing && this.pobMonorepoConfig.codecov,
|
|
@@ -295,7 +304,7 @@ export default class PobMonorepoGenerator extends Generator {
|
|
|
295
304
|
documentation: this.pobMonorepoConfig.documentation,
|
|
296
305
|
storybook: pkg?.devDependencies?.storybook,
|
|
297
306
|
typescript: this.pobMonorepoConfig.typescript,
|
|
298
|
-
build:
|
|
307
|
+
build: hasRootBuild,
|
|
299
308
|
testing: this.pobMonorepoConfig.testing,
|
|
300
309
|
testRunner: this.pobMonorepoConfig.testRunner,
|
|
301
310
|
packageManager: this.options.packageManager,
|
|
@@ -354,7 +363,7 @@ export default class PobMonorepoGenerator extends Generator {
|
|
|
354
363
|
enable: true,
|
|
355
364
|
packageManager: this.options.packageManager,
|
|
356
365
|
enablePublish: !this.options.isAppProject,
|
|
357
|
-
|
|
366
|
+
build: hasRootBuild,
|
|
358
367
|
isMonorepo: true,
|
|
359
368
|
ci: this.pobMonorepoConfig.ci,
|
|
360
369
|
disableYarnGitCache: this.options.disableYarnGitCache,
|
|
@@ -376,9 +385,11 @@ export default class PobMonorepoGenerator extends Generator {
|
|
|
376
385
|
|
|
377
386
|
if (platform !== "win32") {
|
|
378
387
|
execSync(
|
|
379
|
-
`rm -Rf ${["lib-*", "coverage", "docs"].filter(Boolean).join(" ")}`,
|
|
388
|
+
`rm -Rf ${["lib-*", "coverage", "generated-docs"].filter(Boolean).join(" ")}`,
|
|
380
389
|
);
|
|
381
390
|
}
|
|
391
|
+
|
|
392
|
+
removeLegacyGeneratedDocs((path) => this.destinationPath(path));
|
|
382
393
|
}
|
|
383
394
|
|
|
384
395
|
async writing() {
|
|
@@ -443,6 +454,9 @@ export default class PobMonorepoGenerator extends Generator {
|
|
|
443
454
|
this.fs.writeJSON(this.destinationPath("package.json"), pkg);
|
|
444
455
|
}
|
|
445
456
|
|
|
457
|
+
this.composeWith("pob:core:node", {
|
|
458
|
+
onlyLatestLTS: this.options.onlyLatestLTS,
|
|
459
|
+
});
|
|
446
460
|
this.composeWith("pob:core:sort-package");
|
|
447
461
|
}
|
|
448
462
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": [],
|
|
3
3
|
"references": [
|
|
4
|
-
<% if (hasTools) { -%>
|
|
5
|
-
{ "path": "tsconfig.tools.json" }<%= packagePaths.length > 0 ? ',' : '' %>
|
|
6
|
-
<% } -%>
|
|
7
4
|
<% packagePaths.forEach((packagePath, index) => { -%>
|
|
8
|
-
{ "path": "<%= packagePath %>/tsconfig<%= tsConfigSuffix ? `.${tsConfigSuffix}` : '' %>.json" }<%= index === packagePaths.length -1 ? '' : ',' %>
|
|
5
|
+
{ "path": "<%= packagePath %>/tsconfig<%= tsConfigSuffix ? `.${tsConfigSuffix}` : '' %>.json" }<%= index === packagePaths.length -1 && !hasTools ? '' : ',' %>
|
|
9
6
|
<% }) -%>
|
|
7
|
+
<% if (hasTools) { -%>
|
|
8
|
+
{ "path": "tsconfig.tools.json" }
|
|
9
|
+
<% } -%>
|
|
10
10
|
]
|
|
11
11
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
"@pob/root/tsconfigs/targets/node-<%= nodeVersion %>.json"
|
|
5
5
|
],
|
|
6
6
|
"include": [
|
|
7
|
+
"*.config.js",
|
|
7
8
|
"*.config.ts",
|
|
8
9
|
"*.config.mts",
|
|
9
10
|
"*.config.cts",
|
|
@@ -13,7 +14,10 @@
|
|
|
13
14
|
<% workspaceGlobs.forEach((workspaceGlob, index) => { -%>
|
|
14
15
|
"<%= workspaceGlob %>/scripts/**/*.ts",
|
|
15
16
|
"<%= workspaceGlob %>/scripts/**/*.mts",
|
|
16
|
-
"<%= workspaceGlob %>/scripts/**/*.cts"
|
|
17
|
+
"<%= workspaceGlob %>/scripts/**/*.cts",
|
|
18
|
+
"<%= workspaceGlob %>/e2e/**/*.ts",
|
|
19
|
+
"<%= workspaceGlob %>/e2e/**/*.mts",
|
|
20
|
+
"<%= workspaceGlob %>/e2e/**/*.cts"<%= index === workspaceGlobs.length - 1 ? '' : ',' %>
|
|
17
21
|
<% }) -%>
|
|
18
22
|
],
|
|
19
23
|
"compilerOptions": {
|
|
@@ -96,9 +96,10 @@ export default class MonorepoWorkspacesGenerator extends Generator {
|
|
|
96
96
|
const packageManager = this.options.packageManager;
|
|
97
97
|
|
|
98
98
|
packageUtils.addScripts(pkg, {
|
|
99
|
-
lint: `${packageManager} run format && ${packageManager} run lint:eslint`,
|
|
99
|
+
lint: `${packageManager} run format && ${packageManager} run lint:oxlint && ${packageManager} run lint:eslint`,
|
|
100
100
|
format: "oxfmt",
|
|
101
101
|
"format:check": "oxfmt --check .",
|
|
102
|
+
"lint:oxlint": monorepoConfig && monorepoConfig.eslint && "oxlint",
|
|
102
103
|
"lint:eslint":
|
|
103
104
|
monorepoConfig &&
|
|
104
105
|
monorepoConfig.eslint &&
|
package/lib/pob.js
CHANGED
|
@@ -31,6 +31,7 @@ import CoreEditorConfigGenerator from "./generators/core/editorconfig/CoreEditor
|
|
|
31
31
|
import CoreGitGenerator from "./generators/core/git/CoreGitGenerator.js";
|
|
32
32
|
import CoreGitGithubGenerator from "./generators/core/git/generators/github/CoreGitGithubGenerator.js";
|
|
33
33
|
import CoreGitignoreGenerator from "./generators/core/gitignore/CoreGitignoreGenerator.js";
|
|
34
|
+
import CoreNodeGenerator from "./generators/core/node/CoreNodeGenerator.js";
|
|
34
35
|
import CoreNpmGenerator from "./generators/core/npm/CoreNpmGenerator.js";
|
|
35
36
|
import CorePackageGenerator from "./generators/core/package/CorePackageGenerator.js";
|
|
36
37
|
import CorePnpmGenerator from "./generators/core/pnpm/CorePnpmGenerator.js";
|
|
@@ -183,6 +184,11 @@ env.registerStub(
|
|
|
183
184
|
"pob:core:gitignore",
|
|
184
185
|
`${__dirname}/generators/core/gitignore/CoreGitignoreGenerator.js`,
|
|
185
186
|
);
|
|
187
|
+
env.registerStub(
|
|
188
|
+
CoreNodeGenerator,
|
|
189
|
+
"pob:core:node",
|
|
190
|
+
`${__dirname}/generators/core/node/CoreNodeGenerator.js`,
|
|
191
|
+
);
|
|
186
192
|
env.registerStub(
|
|
187
193
|
CoreNpmGenerator,
|
|
188
194
|
"pob:core:npm",
|
package/lib/utils/git.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
export const isTrackedInGit = (cwd, path) => {
|
|
4
|
+
try {
|
|
5
|
+
return (
|
|
6
|
+
execFileSync("git", ["ls-files", "--", path], {
|
|
7
|
+
cwd,
|
|
8
|
+
encoding: "utf8",
|
|
9
|
+
}).trim() !== ""
|
|
10
|
+
);
|
|
11
|
+
} catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Removes a path from the git index, keeping it on disk. Used to migrate
|
|
18
|
+
* repositories where the build output was committed.
|
|
19
|
+
*/
|
|
20
|
+
export const removeFromGitIndex = (cwd, path) => {
|
|
21
|
+
if (!isTrackedInGit(cwd, path)) return false;
|
|
22
|
+
|
|
23
|
+
execFileSync("git", ["rm", "-r", "--cached", "--quiet", "--", path], { cwd });
|
|
24
|
+
console.log(`removed ${path} from git, it is no longer committed`);
|
|
25
|
+
|
|
26
|
+
return true;
|
|
27
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { existsSync, rmSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
const GENERATED_MARKERS = [
|
|
4
|
+
".nojekyll",
|
|
5
|
+
"assets",
|
|
6
|
+
"index.html",
|
|
7
|
+
"coverage.lcov",
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Remove the legacy generated "docs" directory, which is now "generated-docs".
|
|
12
|
+
* Only removes it when it still looks generated, so that a hand-written
|
|
13
|
+
* markdown "docs" directory is left untouched.
|
|
14
|
+
*
|
|
15
|
+
* @param {(path: string) => string} destinationPath
|
|
16
|
+
*/
|
|
17
|
+
export default function removeLegacyGeneratedDocs(destinationPath) {
|
|
18
|
+
const docsPath = destinationPath("docs");
|
|
19
|
+
if (!existsSync(docsPath)) return;
|
|
20
|
+
if (
|
|
21
|
+
!GENERATED_MARKERS.some((marker) => existsSync(`${docsPath}/${marker}`))
|
|
22
|
+
) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
rmSync(docsPath, { recursive: true, force: true });
|
|
26
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import removeLegacyGeneratedDocs from "./legacyGeneratedDocs.js";
|
|
6
|
+
|
|
7
|
+
async function prepareDocs(files) {
|
|
8
|
+
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "pob-"));
|
|
9
|
+
if (files) {
|
|
10
|
+
await fs.mkdir(path.join(tmpDir, "docs"), { recursive: true });
|
|
11
|
+
for (const file of files) {
|
|
12
|
+
await fs.writeFile(path.join(tmpDir, "docs", file), "");
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return tmpDir;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const exists = (docsPath) =>
|
|
19
|
+
fs
|
|
20
|
+
.stat(docsPath)
|
|
21
|
+
.then(() => true)
|
|
22
|
+
.catch(() => false);
|
|
23
|
+
|
|
24
|
+
const run = (tmpDir) =>
|
|
25
|
+
removeLegacyGeneratedDocs((destination) => path.join(tmpDir, destination));
|
|
26
|
+
|
|
27
|
+
describe("removeLegacyGeneratedDocs", () => {
|
|
28
|
+
it.each([".nojekyll", "index.html", "coverage.lcov"])(
|
|
29
|
+
"removes docs generated by typedoc or coverage, detected by %s",
|
|
30
|
+
async (marker) => {
|
|
31
|
+
const tmp = await prepareDocs([marker]);
|
|
32
|
+
run(tmp);
|
|
33
|
+
expect(await exists(path.join(tmp, "docs"))).toBe(false);
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
it("removes docs detected by the typedoc assets directory", async () => {
|
|
38
|
+
const tmp = await prepareDocs([]);
|
|
39
|
+
await fs.mkdir(path.join(tmp, "docs/assets"), { recursive: true });
|
|
40
|
+
run(tmp);
|
|
41
|
+
expect(await exists(path.join(tmp, "docs"))).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("keeps hand written documentation", async () => {
|
|
45
|
+
const tmp = await prepareDocs(["guide.md", "README.md"]);
|
|
46
|
+
run(tmp);
|
|
47
|
+
expect(await fs.readdir(path.join(tmp, "docs"))).toEqual([
|
|
48
|
+
"README.md",
|
|
49
|
+
"guide.md",
|
|
50
|
+
]);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("does nothing when there is no docs directory", async () => {
|
|
54
|
+
const tmp = await prepareDocs(undefined);
|
|
55
|
+
expect(() => run(tmp)).not.toThrow();
|
|
56
|
+
expect(await exists(path.join(tmp, "docs"))).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import semver from "semver";
|
|
2
|
+
import { latestLTS, maintenanceLTS } from "./nodeVersions.js";
|
|
3
|
+
import * as packageUtils from "./package.js";
|
|
4
|
+
|
|
5
|
+
// 22.18.0 is the version with strip typescript out of experimental status
|
|
6
|
+
const minVersionForMajor = new Map([
|
|
7
|
+
["22", "22.18.0"],
|
|
8
|
+
["24", "24.14.1"],
|
|
9
|
+
["26", "26.0.0"],
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
const legacyMajors = ["4", "6", "8", "10", "12", "14", "16", "18", "20"];
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Min node major supported, from pob envs when defined, from the LTS otherwise.
|
|
16
|
+
*/
|
|
17
|
+
export const getEnvsMinNodeMajor = (envs, onlyLatestLTS) => {
|
|
18
|
+
if (!envs) return onlyLatestLTS ? latestLTS : maintenanceLTS;
|
|
19
|
+
return String(
|
|
20
|
+
Math.min(
|
|
21
|
+
...envs
|
|
22
|
+
.filter((env) => env.target === "node")
|
|
23
|
+
.map((env) => Number(env.version)),
|
|
24
|
+
),
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Min node major of a range, undefined when missing or not parseable
|
|
30
|
+
* (workspace:*, catalog:, npm: alias...).
|
|
31
|
+
*/
|
|
32
|
+
export const getMinMajor = (range) => {
|
|
33
|
+
if (!range) return undefined;
|
|
34
|
+
try {
|
|
35
|
+
const minVersion = semver.minVersion(range);
|
|
36
|
+
return minVersion ? semver.major(minVersion) : undefined;
|
|
37
|
+
} catch {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* engines.node value for a min node major. When envs are not defined, an
|
|
44
|
+
* already higher engines.node is kept.
|
|
45
|
+
*/
|
|
46
|
+
export const resolveEnginesNode = (
|
|
47
|
+
currentEnginesNode,
|
|
48
|
+
minNodeMajor,
|
|
49
|
+
hasEnvs,
|
|
50
|
+
) => {
|
|
51
|
+
const major = legacyMajors.includes(String(minNodeMajor))
|
|
52
|
+
? maintenanceLTS
|
|
53
|
+
: String(minNodeMajor);
|
|
54
|
+
const minVersion = minVersionForMajor.get(major);
|
|
55
|
+
if (!minVersion) {
|
|
56
|
+
throw new Error(`Invalid min node version: ${minNodeMajor}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!hasEnvs) {
|
|
60
|
+
const currentMinMajor = getMinMajor(currentEnginesNode);
|
|
61
|
+
if (currentMinMajor !== undefined && currentMinMajor > Number(major)) {
|
|
62
|
+
return currentEnginesNode;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return `>=${minVersion}`;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Updates "@types/node" when it is lower than engines.node min major.
|
|
71
|
+
* Never adds it, never lowers devDependencies.
|
|
72
|
+
*/
|
|
73
|
+
export const updateTypesNodeFromEngines = (pkg) => {
|
|
74
|
+
const minMajor = getMinMajor(pkg.engines?.node);
|
|
75
|
+
if (minMajor === undefined) return;
|
|
76
|
+
const range = `>=${minMajor}.0.0`;
|
|
77
|
+
|
|
78
|
+
if (pkg.dependencies?.["@types/node"]) {
|
|
79
|
+
pkg.dependencies["@types/node"] = range;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const currentDevVersion = pkg.devDependencies?.["@types/node"];
|
|
83
|
+
if (currentDevVersion) {
|
|
84
|
+
const currentMinMajor = getMinMajor(currentDevVersion);
|
|
85
|
+
if (currentMinMajor !== undefined && currentMinMajor < minMajor) {
|
|
86
|
+
pkg.devDependencies["@types/node"] = range;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Sets engines.node from pob envs, then keeps "@types/node" in sync with it.
|
|
93
|
+
*/
|
|
94
|
+
export const updateNodeEngines = (pkg, { onlyLatestLTS } = {}) => {
|
|
95
|
+
const envs = pkg.pob?.envs || pkg.pob?.babelEnvs;
|
|
96
|
+
const hasTargetNode = envs?.some((env) => env.target === "node");
|
|
97
|
+
|
|
98
|
+
if (!pkg.engines) pkg.engines = {};
|
|
99
|
+
|
|
100
|
+
if (hasTargetNode || !envs) {
|
|
101
|
+
pkg.engines.node = resolveEnginesNode(
|
|
102
|
+
pkg.engines.node,
|
|
103
|
+
getEnvsMinNodeMajor(envs, onlyLatestLTS),
|
|
104
|
+
!!envs,
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
updateTypesNodeFromEngines(pkg);
|
|
108
|
+
} else {
|
|
109
|
+
packageUtils.removeDependencies(pkg, ["@types/node"]);
|
|
110
|
+
packageUtils.removeDevDependencies(pkg, ["@types/node"]);
|
|
111
|
+
|
|
112
|
+
// Supports oldest current or active LTS version of node
|
|
113
|
+
const minVersion = minVersionForMajor.get(
|
|
114
|
+
onlyLatestLTS ? latestLTS : maintenanceLTS,
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
if (
|
|
118
|
+
!pkg.engines.node ||
|
|
119
|
+
semver.lt(semver.minVersion(pkg.engines.node), minVersion)
|
|
120
|
+
) {
|
|
121
|
+
pkg.engines.node = `>=${minVersion}`;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
};
|