pob 39.0.0 → 39.1.1

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.
@@ -62,8 +62,6 @@ jobs:
62
62
 
63
63
  - name: Install pnpm
64
64
  uses: pnpm/action-setup@v6
65
- with:
66
- version: 12
67
65
  <% } -%>
68
66
 
69
67
  - uses: actions/setup-node@v7
@@ -1,7 +1,7 @@
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 3 days ago
4
- minimumReleaseAge = 259200 # seconds - in #23162 it'll allow "3d" too
3
+ # Only install package versions published at least 2.5 days ago
4
+ minimumReleaseAge = 216000 # seconds
5
5
  minimumReleaseAgeExcludes = [
6
6
  "@pob/root",
7
7
  "@pob/esbuild",
@@ -24,8 +24,6 @@ jobs:
24
24
  <% } else if (packageManager === 'pnpm') { -%>
25
25
  - name: Install pnpm
26
26
  uses: pnpm/action-setup@v6
27
- with:
28
- version: 12
29
27
 
30
28
  <% } -%>
31
29
  - uses: actions/setup-node@v7
@@ -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
@@ -28,8 +28,6 @@ jobs:
28
28
  <% } else if (packageManager === 'pnpm') { -%>
29
29
  - name: Install pnpm
30
30
  uses: pnpm/action-setup@v6
31
- with:
32
- version: 12
33
31
 
34
32
  <% } -%>
35
33
  - name: Use Node.js ${{ matrix.node-version }}
@@ -1,11 +1,48 @@
1
+ import { execFileSync } from "node:child_process";
1
2
  import sortObject from "@pob/sort-object";
2
- import { FAILSAFE_SCHEMA, dump, loadAll } from "js-yaml";
3
- import { lt } from "semver";
3
+ import { FAILSAFE_SCHEMA, dump, load, loadAll } from "js-yaml";
4
+ import { satisfies } from "semver";
4
5
  import Generator from "yeoman-generator";
5
6
  import { writeAndFormat } from "../../../utils/writeAndFormat.js";
6
7
 
8
+ const pnpmVersionRange = "^12.0.0";
9
+
10
+ // pnpm 12 writes the pnpm version in a first document of pnpm-lock.yaml when
11
+ // devEngines.packageManager is not ignored. Removes it when it has nothing
12
+ // else (no config dependencies).
13
+ const removePackageManagerLockfileDocument = (lockfile) => {
14
+ if (!lockfile.startsWith("---\n")) return lockfile;
15
+ const end = lockfile.indexOf("\n---\n", 4);
16
+ if (end === -1) return lockfile;
17
+ const envDocument = load(lockfile.slice(4, end), { schema: FAILSAFE_SCHEMA });
18
+ const importer = envDocument?.importers?.["."] ?? {};
19
+ const hasOtherEntries = Object.keys(importer).some(
20
+ (key) =>
21
+ key !== "packageManagerDependencies" && key !== "configDependencies",
22
+ );
23
+ if (
24
+ hasOtherEntries ||
25
+ Object.keys(importer.configDependencies ?? {}).length > 0
26
+ ) {
27
+ return lockfile;
28
+ }
29
+ return lockfile.slice(end + "\n---\n".length);
30
+ };
31
+
32
+ const getRunningPnpmVersion = (cwd) => {
33
+ try {
34
+ return execFileSync("pnpm", ["--version"], {
35
+ cwd,
36
+ encoding: "utf8",
37
+ }).trim();
38
+ } catch {
39
+ return null;
40
+ }
41
+ };
42
+
7
43
  const minimumReleaseAgeExcludePackages = [
8
44
  "@pob/*",
45
+ "pob",
9
46
  "pob-dependencies",
10
47
  "check-package-dependencies",
11
48
  "alouette",
@@ -38,12 +75,24 @@ export default class CorePnpmGenerator extends Generator {
38
75
  const pkg = this.fs.readJSON(this.destinationPath("package.json"));
39
76
 
40
77
  if (this.options.enable) {
41
- if (
42
- pkg.packageManager &&
43
- (!pkg.packageManager.startsWith("pnpm@") ||
44
- lt(pkg.packageManager.slice("pnpm@".length), "12.0.0"))
45
- ) {
46
- delete pkg.packageManager;
78
+ // devEngines.packageManager is read by pnpm/action-setup. onFail is
79
+ // "ignore": otherwise pnpm writes its version in pnpm-lock.yaml and it
80
+ // has to be updated manually. The version is checked by engines.pnpm.
81
+ delete pkg.packageManager;
82
+ pkg.devEngines = {
83
+ ...pkg.devEngines,
84
+ packageManager: {
85
+ name: "pnpm",
86
+ version: pnpmVersionRange,
87
+ onFail: "ignore",
88
+ },
89
+ };
90
+
91
+ const lockfilePath = this.destinationPath("pnpm-lock.yaml");
92
+ if (this.fs.exists(lockfilePath)) {
93
+ const lockfile = this.fs.read(lockfilePath);
94
+ const newLockfile = removePackageManagerLockfileDocument(lockfile);
95
+ if (newLockfile !== lockfile) this.fs.write(lockfilePath, newLockfile);
47
96
  }
48
97
 
49
98
  const configString = this.fs.read(
@@ -81,7 +130,7 @@ export default class CorePnpmGenerator extends Generator {
81
130
  delete config.packages;
82
131
  }
83
132
  config.savePrefix = this.options.type === "app" ? "" : "^";
84
- config.minimumReleaseAge = 1440 * 3; // 3 days in minutes
133
+ config.minimumReleaseAge = 1440 * 2.5; // 2.5 days in minutes
85
134
  config.minimumReleaseAgeExclude = minimumReleaseAgeExcludePackages;
86
135
  config.dedupePeerDependents = true;
87
136
  config.nodeLinker = "hoisted";
@@ -95,6 +144,10 @@ export default class CorePnpmGenerator extends Generator {
95
144
  if (pkg.packageManager?.startsWith("pnpm@")) {
96
145
  delete pkg.packageManager;
97
146
  }
147
+ if (pkg.devEngines?.packageManager?.name === "pnpm") {
148
+ delete pkg.devEngines.packageManager;
149
+ if (Object.keys(pkg.devEngines).length === 0) delete pkg.devEngines;
150
+ }
98
151
  this.fs.delete("pnpm-lock.yaml");
99
152
  this.fs.delete("pnpm-workspace.yaml");
100
153
  }
@@ -109,11 +162,23 @@ export default class CorePnpmGenerator extends Generator {
109
162
  `pnpm-workspace.yaml: set allowBuilds to true or false for ${this.pendingAllowBuilds.join(", ")}`,
110
163
  );
111
164
  }
165
+ // the running pnpm can be older than the version required by pob, for
166
+ // example in the @pob/root renovate workflow after a pnpm major update
167
+ const runningPnpmVersion = getRunningPnpmVersion(this.destinationPath());
168
+ const pnpmArgs =
169
+ runningPnpmVersion && satisfies(runningPnpmVersion, pnpmVersionRange)
170
+ ? []
171
+ : ["with", pnpmVersionRange];
172
+
112
173
  // pob just modified package.json: the lockfile must be allowed to update,
113
174
  // in particular in the automatic update GitHub Actions workflow (CI
114
175
  // defaults to frozen lockfile)
115
- this.spawnSync("pnpm", ["install", "--no-frozen-lockfile"], {});
116
- this.spawnSync("pnpm", ["dedupe"], {});
176
+ this.spawnSync(
177
+ "pnpm",
178
+ [...pnpmArgs, "install", "--no-frozen-lockfile"],
179
+ {},
180
+ );
181
+ this.spawnSync("pnpm", [...pnpmArgs, "dedupe"], {});
117
182
 
118
183
  this.fs.delete("package-lock.json");
119
184
  this.fs.delete("yarn.lock");
@@ -122,11 +187,11 @@ export default class CorePnpmGenerator extends Generator {
122
187
 
123
188
  if (pkg.scripts?.preversion) {
124
189
  try {
125
- this.spawnSync("pnpm", ["run", "preversion"]);
190
+ this.spawnSync("pnpm", [...pnpmArgs, "run", "preversion"]);
126
191
  } catch {}
127
192
  } else if (pkg.scripts?.build) {
128
193
  try {
129
- this.spawnSync("pnpm", ["run", "build"]);
194
+ this.spawnSync("pnpm", [...pnpmArgs, "run", "build"]);
130
195
  } catch {}
131
196
  }
132
197
  }
@@ -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 * 3; // 3 days
186
+ config.npmMinimalAgeGate = 1440 * 2.5; // 2.5 days
187
187
  config.npmPreapprovedPackages = [
188
188
  "@pob/*",
189
189
  "pob-dependencies",
@@ -86,10 +86,13 @@ export default class MonorepoWorkspacesGenerator extends Generator {
86
86
  pkg.engines.yarn = "< 0.0.0";
87
87
  pkg.engines.npm = ">= 6.4.0";
88
88
  } else if (this.options.packageManager === "pnpm") {
89
+ // checks the version locally: devEngines.packageManager is ignored by
90
+ // pnpm (see pob:core:pnpm)
89
91
  if (!pkg.engines) pkg.engines = {};
90
92
  pkg.engines.pnpm = ">= 12.0.0";
91
93
  delete pkg.engines.yarn;
92
94
  } else if (pkg.engines) {
95
+ delete pkg.engines.pnpm;
93
96
  delete pkg.engines.yarn;
94
97
  }
95
98
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pob",
3
- "version": "39.0.0",
3
+ "version": "39.1.1",
4
4
  "description": "Pile of bones, library generator with git/babel/typescript/typedoc/readme/vitest",
5
5
  "keywords": [
6
6
  "skeleton"
@@ -58,7 +58,7 @@
58
58
  "yeoman-generator": "10.0.1"
59
59
  },
60
60
  "devDependencies": {
61
- "@pob/root": "27.14.0",
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"