pob 38.13.0 → 39.1.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/common/release/templates/workflow-release.yml.ejs +0 -2
- package/lib/generators/core/bun/templates/bunfig.toml.ejs +19 -3
- package/lib/generators/core/ci/templates/github-action-documentation-workflow.yml.ejs +0 -2
- package/lib/generators/core/ci/templates/github-action-push-workflow-split.yml.ejs +0 -10
- package/lib/generators/core/ci/templates/github-action-push-workflow.yml.ejs +0 -2
- package/lib/generators/core/pnpm/CorePnpmGenerator.js +18 -9
- package/lib/generators/core/yarn/CoreYarnGenerator.js +1 -1
- package/lib/generators/lib/readme/LibReadmeGenerator.js +2 -35
- package/lib/generators/monorepo/workspaces/MonorepoWorkspacesGenerator.js +5 -18
- package/lib/utils/readmeContent.js +52 -0
- package/lib/utils/readmeContent.test.js +167 -0
- package/package.json +9 -9
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Generated by pob: do not edit, it is overwritten on each pob run.
|
|
2
2
|
[install]
|
|
3
|
-
# Only install package versions published at least
|
|
4
|
-
minimumReleaseAge =
|
|
5
|
-
minimumReleaseAgeExcludes = [
|
|
3
|
+
# Only install package versions published at least 2.5 days ago
|
|
4
|
+
minimumReleaseAge = 216000 # seconds
|
|
5
|
+
minimumReleaseAgeExcludes = [
|
|
6
|
+
"@pob/root",
|
|
7
|
+
"@pob/esbuild",
|
|
8
|
+
"@pob/rollup",
|
|
9
|
+
"@pob/rollup-esbuild",
|
|
10
|
+
"@pob/rollup-typescript",
|
|
11
|
+
"@pob/sort-object",
|
|
12
|
+
"@pob/sort-pkg",
|
|
13
|
+
"@pob/version",
|
|
14
|
+
"pob-dependencies",
|
|
15
|
+
"alouette",
|
|
16
|
+
"alouette-icons",
|
|
17
|
+
"nightingale",
|
|
18
|
+
"nightingale-logger",
|
|
19
|
+
"nightingale-levels",
|
|
20
|
+
"nightingale-types",
|
|
21
|
+
]
|
|
@@ -25,8 +25,6 @@ jobs:
|
|
|
25
25
|
<% } else if (packageManager === 'pnpm') { -%>
|
|
26
26
|
- name: Install pnpm
|
|
27
27
|
uses: pnpm/action-setup@v6
|
|
28
|
-
with:
|
|
29
|
-
version: 12
|
|
30
28
|
|
|
31
29
|
<% } -%>
|
|
32
30
|
- uses: actions/setup-node@v7
|
|
@@ -70,8 +68,6 @@ jobs:
|
|
|
70
68
|
<% } else if (packageManager === 'pnpm') { -%>
|
|
71
69
|
- name: Install pnpm
|
|
72
70
|
uses: pnpm/action-setup@v6
|
|
73
|
-
with:
|
|
74
|
-
version: 12
|
|
75
71
|
|
|
76
72
|
<% } -%>
|
|
77
73
|
- uses: actions/setup-node@v7
|
|
@@ -117,8 +113,6 @@ jobs:
|
|
|
117
113
|
<% } else if (packageManager === 'pnpm') { -%>
|
|
118
114
|
- name: Install pnpm
|
|
119
115
|
uses: pnpm/action-setup@v6
|
|
120
|
-
with:
|
|
121
|
-
version: 12
|
|
122
116
|
|
|
123
117
|
<% } -%>
|
|
124
118
|
- uses: actions/setup-node@v7
|
|
@@ -183,8 +177,6 @@ jobs:
|
|
|
183
177
|
<% } else if (packageManager === 'pnpm') { -%>
|
|
184
178
|
- name: Install pnpm
|
|
185
179
|
uses: pnpm/action-setup@v6
|
|
186
|
-
with:
|
|
187
|
-
version: 12
|
|
188
180
|
|
|
189
181
|
<% } -%>
|
|
190
182
|
- uses: actions/setup-node@v7
|
|
@@ -259,8 +251,6 @@ jobs:
|
|
|
259
251
|
<% } else if (packageManager === 'pnpm') { -%>
|
|
260
252
|
- name: Install pnpm
|
|
261
253
|
uses: pnpm/action-setup@v6
|
|
262
|
-
with:
|
|
263
|
-
version: 12
|
|
264
254
|
|
|
265
255
|
<% } -%>
|
|
266
256
|
- uses: actions/setup-node@v7
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import sortObject from "@pob/sort-object";
|
|
2
2
|
import { FAILSAFE_SCHEMA, dump, loadAll } from "js-yaml";
|
|
3
|
-
import { lt } from "semver";
|
|
4
3
|
import Generator from "yeoman-generator";
|
|
5
4
|
import { writeAndFormat } from "../../../utils/writeAndFormat.js";
|
|
6
5
|
|
|
7
6
|
const minimumReleaseAgeExcludePackages = [
|
|
8
7
|
"@pob/*",
|
|
8
|
+
"pob",
|
|
9
9
|
"pob-dependencies",
|
|
10
10
|
"check-package-dependencies",
|
|
11
11
|
"alouette",
|
|
@@ -38,13 +38,18 @@ export default class CorePnpmGenerator extends Generator {
|
|
|
38
38
|
const pkg = this.fs.readJSON(this.destinationPath("package.json"));
|
|
39
39
|
|
|
40
40
|
if (this.options.enable) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
// devEngines.packageManager replaces packageManager: pnpm switches to
|
|
42
|
+
// this version on startup (including when pnpm install is run by pob
|
|
43
|
+
// with an older pnpm), and pnpm/action-setup reads it.
|
|
44
|
+
delete pkg.packageManager;
|
|
45
|
+
pkg.devEngines = {
|
|
46
|
+
...pkg.devEngines,
|
|
47
|
+
packageManager: {
|
|
48
|
+
name: "pnpm",
|
|
49
|
+
version: "^12.0.0",
|
|
50
|
+
onFail: "download",
|
|
51
|
+
},
|
|
52
|
+
};
|
|
48
53
|
|
|
49
54
|
const configString = this.fs.read(
|
|
50
55
|
this.destinationPath("pnpm-workspace.yaml"),
|
|
@@ -81,7 +86,7 @@ export default class CorePnpmGenerator extends Generator {
|
|
|
81
86
|
delete config.packages;
|
|
82
87
|
}
|
|
83
88
|
config.savePrefix = this.options.type === "app" ? "" : "^";
|
|
84
|
-
config.minimumReleaseAge = 1440 *
|
|
89
|
+
config.minimumReleaseAge = 1440 * 2.5; // 2.5 days in minutes
|
|
85
90
|
config.minimumReleaseAgeExclude = minimumReleaseAgeExcludePackages;
|
|
86
91
|
config.dedupePeerDependents = true;
|
|
87
92
|
config.nodeLinker = "hoisted";
|
|
@@ -95,6 +100,10 @@ export default class CorePnpmGenerator extends Generator {
|
|
|
95
100
|
if (pkg.packageManager?.startsWith("pnpm@")) {
|
|
96
101
|
delete pkg.packageManager;
|
|
97
102
|
}
|
|
103
|
+
if (pkg.devEngines?.packageManager?.name === "pnpm") {
|
|
104
|
+
delete pkg.devEngines.packageManager;
|
|
105
|
+
if (Object.keys(pkg.devEngines).length === 0) delete pkg.devEngines;
|
|
106
|
+
}
|
|
98
107
|
this.fs.delete("pnpm-lock.yaml");
|
|
99
108
|
this.fs.delete("pnpm-workspace.yaml");
|
|
100
109
|
}
|
|
@@ -183,7 +183,7 @@ export default class CoreYarnGenerator extends Generator {
|
|
|
183
183
|
config.defaultSemverRangePrefix = this.options.type === "app" ? "" : "^";
|
|
184
184
|
delete config.enableMessageNames; // was a config for yarn < 4
|
|
185
185
|
config.nodeLinker = this.options.yarnNodeLinker;
|
|
186
|
-
config.npmMinimalAgeGate = 1440 *
|
|
186
|
+
config.npmMinimalAgeGate = 1440 * 2.5; // 2.5 days
|
|
187
187
|
config.npmPreapprovedPackages = [
|
|
188
188
|
"@pob/*",
|
|
189
189
|
"pob-dependencies",
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
/* oxlint-disable regexp/match-any */
|
|
2
|
-
/* oxlint-disable regexp/no-super-linear-backtracking */
|
|
3
1
|
import camelCase from "lodash.camelcase";
|
|
4
2
|
import Generator from "yeoman-generator";
|
|
5
3
|
import inMonorepo from "../../../utils/inMonorepo.js";
|
|
6
4
|
import * as packageUtils from "../../../utils/package.js";
|
|
5
|
+
import { extractLibReadmeContent } from "../../../utils/readmeContent.js";
|
|
7
6
|
import { copyAndFormatTpl } from "../../../utils/writeAndFormat.js";
|
|
8
7
|
|
|
9
8
|
export default class LibReadmeGenerator extends Generator {
|
|
@@ -49,39 +48,7 @@ export default class LibReadmeGenerator extends Generator {
|
|
|
49
48
|
|
|
50
49
|
if (this.fs.exists(readmePath)) {
|
|
51
50
|
const readmeFullContent = this.fs.read(readmePath);
|
|
52
|
-
content = readmeFullContent
|
|
53
|
-
/^<h1 align="center"[^#*]+([^]+)\[npm-image\]:/,
|
|
54
|
-
);
|
|
55
|
-
if (!content) {
|
|
56
|
-
content = readmeFullContent.match(
|
|
57
|
-
/^<h1 align="center"[^#*]+([^]+)\[daviddm-image\]:/,
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
if (!content) {
|
|
61
|
-
content = readmeFullContent.match(
|
|
62
|
-
/^<h3 align="center"[^#*]+([^]+)\[npm-image\]:/,
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
if (!content) {
|
|
66
|
-
content = readmeFullContent.match(
|
|
67
|
-
/^<h3 align="center"[^#*]+([^]+)\[daviddm-image\]:/,
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
if (!content) {
|
|
71
|
-
content = readmeFullContent.match(/^<h1 align="center"[^#*]+([^]+)$/);
|
|
72
|
-
}
|
|
73
|
-
if (!content) {
|
|
74
|
-
content = readmeFullContent.match(/^<h3 align="center"[^#*]+([^]+)$/);
|
|
75
|
-
}
|
|
76
|
-
if (!content) content = readmeFullContent.match(/^<h3[^#*]+([^]+)$/);
|
|
77
|
-
if (!content) {
|
|
78
|
-
content = readmeFullContent.match(/^#[^#*]+([^]+)\[npm-image\]:/);
|
|
79
|
-
}
|
|
80
|
-
if (!content) {
|
|
81
|
-
content = readmeFullContent.match(/^#[^#*]+([^]+)\[daviddm-image\]:/);
|
|
82
|
-
}
|
|
83
|
-
if (!content) content = readmeFullContent.match(/^#[^#*]+([^]+)$/);
|
|
84
|
-
content = content ? content[1].trim() : readmeFullContent;
|
|
51
|
+
content = extractLibReadmeContent(readmeFullContent);
|
|
85
52
|
}
|
|
86
53
|
|
|
87
54
|
const author = packageUtils.parsePkgAuthor(pkg);
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
workspacesRunExcluding,
|
|
7
7
|
workspacesRunTopological,
|
|
8
8
|
} from "../../../utils/packageManagerWorkspacesUtils.js";
|
|
9
|
+
import { extractMonorepoReadmeContent } from "../../../utils/readmeContent.js";
|
|
9
10
|
import { copyAndFormatTpl } from "../../../utils/writeAndFormat.js";
|
|
10
11
|
|
|
11
12
|
export default class MonorepoWorkspacesGenerator extends Generator {
|
|
@@ -84,11 +85,9 @@ export default class MonorepoWorkspacesGenerator extends Generator {
|
|
|
84
85
|
if (!pkg.engines) pkg.engines = {};
|
|
85
86
|
pkg.engines.yarn = "< 0.0.0";
|
|
86
87
|
pkg.engines.npm = ">= 6.4.0";
|
|
87
|
-
} else if (this.options.packageManager === "pnpm") {
|
|
88
|
-
if (!pkg.engines) pkg.engines = {};
|
|
89
|
-
pkg.engines.pnpm = ">= 12.0.0";
|
|
90
|
-
delete pkg.engines.yarn;
|
|
91
88
|
} else if (pkg.engines) {
|
|
89
|
+
// the pnpm version is set in devEngines by pob:core:pnpm
|
|
90
|
+
delete pkg.engines.pnpm;
|
|
92
91
|
delete pkg.engines.yarn;
|
|
93
92
|
}
|
|
94
93
|
|
|
@@ -165,19 +164,7 @@ export default class MonorepoWorkspacesGenerator extends Generator {
|
|
|
165
164
|
|
|
166
165
|
if (this.fs.exists(readmePath)) {
|
|
167
166
|
const readmeFullContent = this.fs.read(readmePath);
|
|
168
|
-
|
|
169
|
-
content = readmeFullContent.match(/^<h1 align="center"[^#*]+([^]+)$/);
|
|
170
|
-
if (!content) {
|
|
171
|
-
// oxlint-disable-next-line regexp/no-super-linear-backtracking, regexp/match-any
|
|
172
|
-
content = readmeFullContent.match(/^<h3 align="center"[^#*]+([^]+)$/);
|
|
173
|
-
}
|
|
174
|
-
if (!content) {
|
|
175
|
-
// oxlint-disable-next-line regexp/no-super-linear-backtracking, regexp/match-any
|
|
176
|
-
content = readmeFullContent.match(/^<h3[^#*]+([^]+)$/);
|
|
177
|
-
}
|
|
178
|
-
// oxlint-disable-next-line regexp/no-super-linear-backtracking, regexp/match-any
|
|
179
|
-
if (!content) content = readmeFullContent.match(/^#[^#*]+([^]+)$/);
|
|
180
|
-
content = content ? content[1].trim() : readmeFullContent;
|
|
167
|
+
content = extractMonorepoReadmeContent(readmeFullContent);
|
|
181
168
|
}
|
|
182
169
|
|
|
183
170
|
return copyAndFormatTpl(
|
|
@@ -185,7 +172,7 @@ export default class MonorepoWorkspacesGenerator extends Generator {
|
|
|
185
172
|
this.templatePath("README.md.ejs"),
|
|
186
173
|
readmePath,
|
|
187
174
|
{
|
|
188
|
-
title: pkg.description,
|
|
175
|
+
title: pkg.description || pkg.name.replace(/-monorepo$/, ""),
|
|
189
176
|
description: "",
|
|
190
177
|
packages: this.packages,
|
|
191
178
|
ci: this.fs.exists(this.destinationPath(".github/workflows/push.yml")),
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Generators regenerate the header of a README and keep the hand-written body
|
|
2
|
+
// that follows it. The body is whatever comes after the generated header, so
|
|
3
|
+
// it is found by matching the header itself — not by looking for the first
|
|
4
|
+
// heading, which loses any prose placed right after the header, and stops early
|
|
5
|
+
// on a `#` or `*` inside the header (a description such as "C# client").
|
|
6
|
+
|
|
7
|
+
/* oxlint-disable regexp/no-super-linear-backtracking, regexp/match-any */
|
|
8
|
+
|
|
9
|
+
// <h1>, optional <p> description, then the packages table
|
|
10
|
+
const monorepoHeaderRegex =
|
|
11
|
+
/^<h1 align="center">[^]*?\n<h3>📦 Packages<\/h3>\n[^|]*(?:\|[^\n]*\n)+([^]*)$/;
|
|
12
|
+
|
|
13
|
+
// <h1>, then the <p> description and badges blocks
|
|
14
|
+
const libHeaderRegex =
|
|
15
|
+
/^<h1 align="center">[^]*?<\/h1>\n(?:\s*<p align="center">[^]*?<\/p>\n)+([^]*)$/;
|
|
16
|
+
|
|
17
|
+
const matchFirst = (content, regexes) => {
|
|
18
|
+
for (const regex of regexes) {
|
|
19
|
+
const match = content.match(regex);
|
|
20
|
+
if (match) return match[1].trim();
|
|
21
|
+
}
|
|
22
|
+
return content;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export function extractMonorepoReadmeContent(readmeFullContent) {
|
|
26
|
+
return matchFirst(readmeFullContent, [
|
|
27
|
+
monorepoHeaderRegex,
|
|
28
|
+
// legacy headers
|
|
29
|
+
/^<h1 align="center"[^#*]+([^]+)$/,
|
|
30
|
+
/^<h3 align="center"[^#*]+([^]+)$/,
|
|
31
|
+
/^<h3[^#*]+([^]+)$/,
|
|
32
|
+
/^#[^#*]+([^]+)$/,
|
|
33
|
+
]);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function extractLibReadmeContent(readmeFullContent) {
|
|
37
|
+
return matchFirst(readmeFullContent, [
|
|
38
|
+
// legacy headers with badges as reference links at the end
|
|
39
|
+
/^<h1 align="center"[^#*]+([^]+)\[npm-image\]:/,
|
|
40
|
+
/^<h1 align="center"[^#*]+([^]+)\[daviddm-image\]:/,
|
|
41
|
+
/^<h3 align="center"[^#*]+([^]+)\[npm-image\]:/,
|
|
42
|
+
/^<h3 align="center"[^#*]+([^]+)\[daviddm-image\]:/,
|
|
43
|
+
libHeaderRegex,
|
|
44
|
+
// legacy headers
|
|
45
|
+
/^<h1 align="center"[^#*]+([^]+)$/,
|
|
46
|
+
/^<h3 align="center"[^#*]+([^]+)$/,
|
|
47
|
+
/^<h3[^#*]+([^]+)$/,
|
|
48
|
+
/^#[^#*]+([^]+)\[npm-image\]:/,
|
|
49
|
+
/^#[^#*]+([^]+)\[daviddm-image\]:/,
|
|
50
|
+
/^#[^#*]+([^]+)$/,
|
|
51
|
+
]);
|
|
52
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { create as createMemFs } from "mem-fs";
|
|
4
|
+
import { create as createEditor } from "mem-fs-editor";
|
|
5
|
+
import {
|
|
6
|
+
extractLibReadmeContent,
|
|
7
|
+
extractMonorepoReadmeContent,
|
|
8
|
+
} from "./readmeContent.js";
|
|
9
|
+
import { copyAndFormatTpl } from "./writeAndFormat.js";
|
|
10
|
+
|
|
11
|
+
const templatePath = (generator) =>
|
|
12
|
+
fileURLToPath(
|
|
13
|
+
new URL(
|
|
14
|
+
`../generators/${generator}/templates/README.md.ejs`,
|
|
15
|
+
import.meta.url,
|
|
16
|
+
),
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
// renders the README exactly as the generator writes it: template, then oxfmt
|
|
20
|
+
async function render(generator, options) {
|
|
21
|
+
const fs = createEditor(createMemFs());
|
|
22
|
+
const destinationPath = "/virtual/README.md";
|
|
23
|
+
await copyAndFormatTpl(fs, templatePath(generator), destinationPath, options);
|
|
24
|
+
return fs.read(destinationPath);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const packages = [
|
|
28
|
+
{ name: "pkg-a", description: "First package" },
|
|
29
|
+
{ name: "pkg-b", description: "Second package" },
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const renderMonorepo = (content, { title = "a monorepo" } = {}) =>
|
|
33
|
+
render("monorepo/workspaces", {
|
|
34
|
+
title,
|
|
35
|
+
description: "",
|
|
36
|
+
packages,
|
|
37
|
+
ci: false,
|
|
38
|
+
content,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const renderLib = (content, options = {}) =>
|
|
42
|
+
render("lib/readme", {
|
|
43
|
+
title: "pkg-a",
|
|
44
|
+
privatePackage: false,
|
|
45
|
+
packageName: "pkg-a",
|
|
46
|
+
camelCaseProjectName: "pkgA",
|
|
47
|
+
description: "First package",
|
|
48
|
+
gitHost: "github",
|
|
49
|
+
gitAccount: "someone",
|
|
50
|
+
gitName: "pkg-a",
|
|
51
|
+
codecov: false,
|
|
52
|
+
documentation: false,
|
|
53
|
+
documentationUrl: undefined,
|
|
54
|
+
testing: false,
|
|
55
|
+
ci: false,
|
|
56
|
+
...options,
|
|
57
|
+
content,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const proseBody = `Every tool here answers the same two questions:
|
|
61
|
+
|
|
62
|
+
- **why is this duplicated?** — which dependents force several versions.
|
|
63
|
+
- **dedupe it** — compute the fixes and apply them.
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
Run it.`;
|
|
68
|
+
|
|
69
|
+
const headingBody = `## About
|
|
70
|
+
|
|
71
|
+
Some text, with **bold**.`;
|
|
72
|
+
|
|
73
|
+
describe("extractMonorepoReadmeContent", () => {
|
|
74
|
+
it.each([
|
|
75
|
+
["a body starting with a heading", headingBody],
|
|
76
|
+
["a body starting with prose", proseBody],
|
|
77
|
+
])("keeps %s through regeneration", async (_, body) => {
|
|
78
|
+
const readme = await renderMonorepo(body);
|
|
79
|
+
expect(extractMonorepoReadmeContent(readme)).toBe(body);
|
|
80
|
+
// a second run is stable
|
|
81
|
+
expect(await renderMonorepo(extractMonorepoReadmeContent(readme))).toBe(
|
|
82
|
+
readme,
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("keeps the body when the title contains # or *", async () => {
|
|
87
|
+
const readme = await renderMonorepo(proseBody, {
|
|
88
|
+
title: "C# tools, **bold**",
|
|
89
|
+
});
|
|
90
|
+
expect(extractMonorepoReadmeContent(readme)).toBe(proseBody);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("extracts nothing from a README without a body", async () => {
|
|
94
|
+
expect(extractMonorepoReadmeContent(await renderMonorepo(""))).toBe("");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// pm-tools README: hand-written prose right after the table lost everything
|
|
98
|
+
// up to the first `*`, i.e. the paragraph and the first bullet's `- `
|
|
99
|
+
it("strips a hand-edited header and keeps the prose after the table", () => {
|
|
100
|
+
const readme = `<h1 align="center">
|
|
101
|
+
pm-tools
|
|
102
|
+
</h1>
|
|
103
|
+
|
|
104
|
+
<p align="center">
|
|
105
|
+
Find out why a dependency is duplicated in a lockfile, and dedupe it.
|
|
106
|
+
</p>
|
|
107
|
+
|
|
108
|
+
<h3>📦 Packages</h3>
|
|
109
|
+
|
|
110
|
+
This repository is a monorepo managed with [bun workspaces](https://bun.com/docs/install/workspaces).
|
|
111
|
+
|
|
112
|
+
| Package | Version | Description |
|
|
113
|
+
| --------------------- | ------- | ---------------- |
|
|
114
|
+
| [pkg-a](packages/pkg-a) | | First package |
|
|
115
|
+
|
|
116
|
+
${proseBody}
|
|
117
|
+
`;
|
|
118
|
+
expect(extractMonorepoReadmeContent(readme)).toBe(proseBody);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("falls back to the first heading for a README not generated by pob", () => {
|
|
122
|
+
expect(extractMonorepoReadmeContent("# title\n\nintro\n\n## Usage\n")).toBe(
|
|
123
|
+
"## Usage",
|
|
124
|
+
);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe("extractLibReadmeContent", () => {
|
|
129
|
+
it.each([
|
|
130
|
+
["a body starting with a heading", headingBody, {}],
|
|
131
|
+
["a body starting with prose", proseBody, {}],
|
|
132
|
+
[
|
|
133
|
+
"a description containing # or *",
|
|
134
|
+
headingBody,
|
|
135
|
+
{ description: "C# **x**" },
|
|
136
|
+
],
|
|
137
|
+
["no description", proseBody, { description: undefined }],
|
|
138
|
+
[
|
|
139
|
+
"an empty badges block",
|
|
140
|
+
proseBody,
|
|
141
|
+
{ privatePackage: true, gitHost: undefined },
|
|
142
|
+
],
|
|
143
|
+
])(
|
|
144
|
+
"keeps the body with %s through regeneration",
|
|
145
|
+
async (_, body, options) => {
|
|
146
|
+
const readme = await renderLib(body, options);
|
|
147
|
+
expect(extractLibReadmeContent(readme)).toBe(body);
|
|
148
|
+
expect(await renderLib(extractLibReadmeContent(readme), options)).toBe(
|
|
149
|
+
readme,
|
|
150
|
+
);
|
|
151
|
+
},
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
it("strips legacy badges reference links", () => {
|
|
155
|
+
const readme = `<h1 align="center">
|
|
156
|
+
pkg-a
|
|
157
|
+
</h1>
|
|
158
|
+
|
|
159
|
+
## Usage
|
|
160
|
+
|
|
161
|
+
Run it.
|
|
162
|
+
|
|
163
|
+
[npm-image]: https://img.shields.io/npm/v/pkg-a.svg
|
|
164
|
+
`;
|
|
165
|
+
expect(extractLibReadmeContent(readme)).toBe("## Usage\n\nRun it.");
|
|
166
|
+
});
|
|
167
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pob",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "39.1.0",
|
|
4
4
|
"description": "Pile of bones, library generator with git/babel/typescript/typedoc/readme/vitest",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"skeleton"
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"./package.json": "./package.json"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@pob/eslint-config": "67.
|
|
35
|
-
"@pob/eslint-config-typescript-react": "67.
|
|
34
|
+
"@pob/eslint-config": "67.12.0",
|
|
35
|
+
"@pob/eslint-config-typescript-react": "67.12.0",
|
|
36
36
|
"@pob/sort-object": "11.2.0",
|
|
37
37
|
"@pob/sort-pkg": "13.2.0",
|
|
38
38
|
"@types/inquirer": "9.0.10",
|
|
@@ -46,25 +46,25 @@
|
|
|
46
46
|
"lodash.camelcase": "^4.3.0",
|
|
47
47
|
"lodash.kebabcase": "^4.1.1",
|
|
48
48
|
"mem-fs": "4.1.5",
|
|
49
|
-
"mem-fs-editor": "12.0
|
|
49
|
+
"mem-fs-editor": "12.1.0",
|
|
50
50
|
"minimist": "1.2.8",
|
|
51
|
-
"oxfmt": "0.
|
|
51
|
+
"oxfmt": "0.72.0",
|
|
52
52
|
"parse-author": "2.0.0",
|
|
53
|
-
"pob-dependencies": "27.
|
|
53
|
+
"pob-dependencies": "27.12.0",
|
|
54
54
|
"semver": "7.8.5",
|
|
55
55
|
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
56
56
|
"validate-npm-package-name": "^8.0.0",
|
|
57
57
|
"yeoman-environment": "6.1.0",
|
|
58
|
-
"yeoman-generator": "
|
|
58
|
+
"yeoman-generator": "10.0.1"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@pob/root": "27.
|
|
61
|
+
"@pob/root": "27.15.0",
|
|
62
62
|
"@types/node": "24.19.1",
|
|
63
63
|
"@typescript/native": "npm:typescript@7.0.2",
|
|
64
64
|
"@yeoman/types": "1.11.1"
|
|
65
65
|
},
|
|
66
66
|
"engines": {
|
|
67
|
-
"node": ">=
|
|
67
|
+
"node": ">=24.14.1"
|
|
68
68
|
},
|
|
69
69
|
"pob": {
|
|
70
70
|
"typescript": "check-only"
|