pob 38.12.0 → 39.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.
- package/lib/generators/app/PobAppGenerator.js +1 -0
- package/lib/generators/common/release/templates/workflow-release.yml.ejs +19 -9
- package/lib/generators/common/typescript/CommonTypescriptGenerator.js +13 -1
- package/lib/generators/core/bun/templates/bunfig.toml.ejs +17 -1
- package/lib/generators/lib/PobLibGenerator.js +1 -0
- package/lib/generators/lib/readme/LibReadmeGenerator.js +2 -35
- package/lib/generators/monorepo/workspaces/MonorepoWorkspacesGenerator.js +3 -14
- package/lib/utils/readmeContent.js +52 -0
- package/lib/utils/readmeContent.test.js +167 -0
- package/package.json +9 -9
|
@@ -267,6 +267,7 @@ export default class PobAppGenerator extends Generator {
|
|
|
267
267
|
updateOnly: this.options.updateOnly,
|
|
268
268
|
resolveJsonModule: true,
|
|
269
269
|
onlyLatestLTS: true,
|
|
270
|
+
packageManager: this.options.packageManager,
|
|
270
271
|
enableHashSlash,
|
|
271
272
|
plugins: (() => {
|
|
272
273
|
if (this.appConfig.type === "next.js") {
|
|
@@ -15,15 +15,25 @@ on:
|
|
|
15
15
|
default: false
|
|
16
16
|
<% if (isMonorepo && isMonorepoIndependent) { -%>
|
|
17
17
|
bump-dependents-highest-as:
|
|
18
|
-
description: "Bump dependents highest as"
|
|
19
|
-
required:
|
|
18
|
+
description: "Bump dependents highest version as"
|
|
19
|
+
required: true
|
|
20
20
|
type: choice
|
|
21
21
|
options:
|
|
22
22
|
- major
|
|
23
23
|
- minor
|
|
24
24
|
- patch
|
|
25
|
-
default:
|
|
25
|
+
default: major
|
|
26
26
|
<% } -%>
|
|
27
|
+
force:
|
|
28
|
+
description: "Force bump all packages, even without changes"
|
|
29
|
+
required: true
|
|
30
|
+
type: choice
|
|
31
|
+
options:
|
|
32
|
+
- none
|
|
33
|
+
- major
|
|
34
|
+
- minor
|
|
35
|
+
- patch
|
|
36
|
+
default: none
|
|
27
37
|
|
|
28
38
|
permissions:
|
|
29
39
|
id-token: write # Required for OIDC
|
|
@@ -92,7 +102,7 @@ jobs:
|
|
|
92
102
|
|
|
93
103
|
- name: New version (dry run)
|
|
94
104
|
if: github.ref == 'refs/heads/main' && inputs.dry-run
|
|
95
|
-
run: <%= packageManagerExec(packageManager, 'pob-version') %> --dry-run<% if (isMonorepo && isMonorepoIndependent) { %> --bump-dependents-highest-as=${{ inputs.bump-dependents-highest-as }}<% } %>
|
|
105
|
+
run: <%= packageManagerExec(packageManager, 'pob-version') %> --dry-run<% if (isMonorepo && isMonorepoIndependent) { %> --bump-dependents-highest-as=${{ inputs.bump-dependents-highest-as }}<% } %> ${{ inputs.force != 'none' && format('--force={0}', inputs.force) || '' }}
|
|
96
106
|
|
|
97
107
|
- name: Configure Git user
|
|
98
108
|
if: github.ref == 'refs/heads/main' && !inputs.dry-run
|
|
@@ -103,7 +113,7 @@ jobs:
|
|
|
103
113
|
- name: New version
|
|
104
114
|
if: github.ref == 'refs/heads/main' && !inputs.dry-run
|
|
105
115
|
run: |
|
|
106
|
-
<%= packageManagerExec(packageManager, 'pob-version') %> <% if (enablePublish && packageManager === "bun") { %>--publish <% } %>--create-release=github
|
|
116
|
+
<%= packageManagerExec(packageManager, 'pob-version') %> <% if (enablePublish && packageManager === "bun") { %>--publish --publish-provenance <% } %>--create-release=github<% if (isMonorepo && isMonorepoIndependent) { %> --bump-dependents-highest-as=${{ inputs.bump-dependents-highest-as }}<% } %> ${{ inputs.force != 'none' && format('--force={0}', inputs.force) || '' }} -m 'chore: release <%- isMonorepoIndependent ? '' : '%v ' %>[skip ci]<%- isMonorepoIndependent ? '\\n\\n%t' : '' %>'
|
|
107
117
|
env:
|
|
108
118
|
POB_GIT_HOOKS: 0
|
|
109
119
|
YARN_ENABLE_IMMUTABLE_INSTALLS: false
|
|
@@ -115,15 +125,15 @@ jobs:
|
|
|
115
125
|
run: |
|
|
116
126
|
<% if (packageManager === 'yarn') { -%>
|
|
117
127
|
<% if (isMonorepo) { -%>
|
|
118
|
-
yarn workspaces foreach --all --parallel --no-private npm publish --tolerate-republish
|
|
128
|
+
yarn workspaces foreach --all --parallel --no-private npm publish --tolerate-republish --provenance
|
|
119
129
|
<% } else { -%>
|
|
120
|
-
yarn npm publish
|
|
130
|
+
yarn npm publish --provenance
|
|
121
131
|
<% } -%>
|
|
122
132
|
<% } else if (packageManager === 'pnpm') { -%>
|
|
123
133
|
<% if (isMonorepo) { -%>
|
|
124
|
-
pnpm -r publish --no-git-checks
|
|
134
|
+
pnpm -r publish --no-git-checks --provenance
|
|
125
135
|
<% } else { -%>
|
|
126
|
-
pnpm publish --no-git-checks
|
|
136
|
+
pnpm publish --no-git-checks --provenance
|
|
127
137
|
<% } -%>
|
|
128
138
|
<% } -%>
|
|
129
139
|
<% } -%>
|
|
@@ -102,6 +102,12 @@ export default class CommonTypescriptGenerator extends Generator {
|
|
|
102
102
|
description: "typescript additional includes",
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
+
this.option("packageManager", {
|
|
106
|
+
type: String,
|
|
107
|
+
default: "yarn",
|
|
108
|
+
description: "yarn, npm, bun, or pnpm",
|
|
109
|
+
});
|
|
110
|
+
|
|
105
111
|
this.option("onlyLatestLTS", {
|
|
106
112
|
type: Boolean,
|
|
107
113
|
required: false,
|
|
@@ -146,6 +152,7 @@ export default class CommonTypescriptGenerator extends Generator {
|
|
|
146
152
|
},
|
|
147
153
|
];
|
|
148
154
|
const withNode = envs.some((env) => env.target === "node");
|
|
155
|
+
const withBun = this.options.packageManager === "bun";
|
|
149
156
|
|
|
150
157
|
const presets = (() => {
|
|
151
158
|
const babelEnvs =
|
|
@@ -172,7 +179,9 @@ export default class CommonTypescriptGenerator extends Generator {
|
|
|
172
179
|
pkg.pob.bundler === false ||
|
|
173
180
|
pkg.pob.bundler === "tsc"
|
|
174
181
|
) {
|
|
175
|
-
return
|
|
182
|
+
return withBun
|
|
183
|
+
? ["@pob/root/tsconfigs/targets/bun.json"]
|
|
184
|
+
: [`@pob/root/tsconfigs/targets/node-${nodeVersion}.json`];
|
|
176
185
|
}
|
|
177
186
|
if (envs && envs.every((env) => env.target === "node")) {
|
|
178
187
|
return [
|
|
@@ -199,6 +208,9 @@ export default class CommonTypescriptGenerator extends Generator {
|
|
|
199
208
|
}
|
|
200
209
|
return ["@pob/root/tsconfigs/targets/webpack.json"];
|
|
201
210
|
}
|
|
211
|
+
if (withBun) {
|
|
212
|
+
return ["@pob/root/tsconfigs/targets/bun.json"];
|
|
213
|
+
}
|
|
202
214
|
return [];
|
|
203
215
|
})();
|
|
204
216
|
|
|
@@ -2,4 +2,20 @@
|
|
|
2
2
|
[install]
|
|
3
3
|
# Only install package versions published at least 3 days ago
|
|
4
4
|
minimumReleaseAge = 259200 # seconds - in #23162 it'll allow "3d" too
|
|
5
|
-
minimumReleaseAgeExcludes = [
|
|
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
|
+
]
|
|
@@ -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 {
|
|
@@ -165,19 +166,7 @@ export default class MonorepoWorkspacesGenerator extends Generator {
|
|
|
165
166
|
|
|
166
167
|
if (this.fs.exists(readmePath)) {
|
|
167
168
|
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;
|
|
169
|
+
content = extractMonorepoReadmeContent(readmeFullContent);
|
|
181
170
|
}
|
|
182
171
|
|
|
183
172
|
return copyAndFormatTpl(
|
|
@@ -185,7 +174,7 @@ export default class MonorepoWorkspacesGenerator extends Generator {
|
|
|
185
174
|
this.templatePath("README.md.ejs"),
|
|
186
175
|
readmePath,
|
|
187
176
|
{
|
|
188
|
-
title: pkg.description,
|
|
177
|
+
title: pkg.description || pkg.name.replace(/-monorepo$/, ""),
|
|
189
178
|
description: "",
|
|
190
179
|
packages: this.packages,
|
|
191
180
|
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.0.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.14.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"
|