@bleedingdev/modern-js-create 3.5.0-ultramodern.2 → 3.5.0-ultramodern.4
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/README.md +9 -5
- package/dist/cjs/ultramodern-tooling/commands.cjs +129 -3
- package/dist/esm/ultramodern-tooling/commands.js +129 -3
- package/dist/esm-node/ultramodern-tooling/commands.js +129 -3
- package/package.json +3 -3
- package/template-workspace/README.md.handlebars +8 -4
- package/template-workspace/pnpm-workspace.yaml.handlebars +3 -0
package/README.md
CHANGED
|
@@ -193,8 +193,8 @@ For strict Effect API migrations, update generated package metadata and Modern
|
|
|
193
193
|
package aliases through the framework command before hand-editing app code:
|
|
194
194
|
|
|
195
195
|
```bash
|
|
196
|
-
pnpm dlx @bleedingdev/modern-js-create@3.5.0-ultramodern.
|
|
197
|
-
migrate-strict-effect --version 3.5.0-ultramodern.
|
|
196
|
+
pnpm dlx @bleedingdev/modern-js-create@3.5.0-ultramodern.4 ultramodern \
|
|
197
|
+
migrate-strict-effect --version 3.5.0-ultramodern.4
|
|
198
198
|
pnpm api:check
|
|
199
199
|
pnpm contract:check
|
|
200
200
|
pnpm check
|
|
@@ -202,7 +202,8 @@ pnpm build
|
|
|
202
202
|
```
|
|
203
203
|
|
|
204
204
|
The command updates `.modernjs/ultramodern.json`, root `modernjs.packageSource`,
|
|
205
|
-
generated Modern package aliases,
|
|
205
|
+
generated Modern package aliases, framework-owned toolchain pins, old direct
|
|
206
|
+
topology metadata, strict Effect pnpm overrides/trust policy, and the pnpm
|
|
206
207
|
lockfile. It does not invent compatibility shims or move business code behind
|
|
207
208
|
your back. If `pnpm api:check` still fails, migrate the source to
|
|
208
209
|
`shared/api.ts`, `api/index.ts`, and `src/api/*-client.ts` and delete
|
|
@@ -210,8 +211,11 @@ your back. If `pnpm api:check` still fails, migrate the source to
|
|
|
210
211
|
|
|
211
212
|
Generated strict Effect workspaces pin the compatible Effect cohort through
|
|
212
213
|
`pnpm-workspace.yaml` overrides: `effect@4.0.0-beta.91` and
|
|
213
|
-
`@effect/vitest@4.0.0-beta.91`.
|
|
214
|
-
|
|
214
|
+
`@effect/vitest@4.0.0-beta.91`. The generated pnpm policy also excludes the
|
|
215
|
+
known `effect@4.0.0-beta.91` and `@effect/opentelemetry@4.0.0-beta.91`
|
|
216
|
+
trusted-publisher to provenance transitions from no-downgrade checks. Do not
|
|
217
|
+
override those in app packages; update the framework cohort when the runtime
|
|
218
|
+
moves.
|
|
215
219
|
|
|
216
220
|
Use `--ultramodern-package-source=install` for published cohort proof and pin a
|
|
217
221
|
specific release with `--ultramodern-package-version` when CI must prove an
|
|
@@ -53,6 +53,7 @@ const external_node_url_namespaceObject = require("node:url");
|
|
|
53
53
|
const external_create_package_root_cjs_namespaceObject = require("../create-package-root.cjs");
|
|
54
54
|
const external_ultramodern_package_source_cjs_namespaceObject = require("../ultramodern-package-source.cjs");
|
|
55
55
|
const mf_validation_cjs_namespaceObject = require("../ultramodern-workspace/mf-validation.cjs");
|
|
56
|
+
const versions_cjs_namespaceObject = require("../ultramodern-workspace/versions.cjs");
|
|
56
57
|
const workspace_scripts_cjs_namespaceObject = require("../ultramodern-workspace/workspace-scripts.cjs");
|
|
57
58
|
const external_config_cjs_namespaceObject = require("./config.cjs");
|
|
58
59
|
const commands_dirname = external_node_path_default().dirname((0, external_node_url_namespaceObject.fileURLToPath)(__rslib_import_meta_url__));
|
|
@@ -198,6 +199,58 @@ function updateModernDependencies(packageJson, packageSource) {
|
|
|
198
199
|
}
|
|
199
200
|
return changed;
|
|
200
201
|
}
|
|
202
|
+
const generatedToolingDependencyPins = new Map([
|
|
203
|
+
[
|
|
204
|
+
'@effect/tsgo',
|
|
205
|
+
versions_cjs_namespaceObject.EFFECT_TSGO_VERSION
|
|
206
|
+
],
|
|
207
|
+
[
|
|
208
|
+
"@typescript/native-preview",
|
|
209
|
+
versions_cjs_namespaceObject.TYPESCRIPT_NATIVE_PREVIEW_VERSION
|
|
210
|
+
],
|
|
211
|
+
[
|
|
212
|
+
'oxfmt',
|
|
213
|
+
versions_cjs_namespaceObject.OXFMT_VERSION
|
|
214
|
+
],
|
|
215
|
+
[
|
|
216
|
+
'oxlint',
|
|
217
|
+
versions_cjs_namespaceObject.OXLINT_VERSION
|
|
218
|
+
],
|
|
219
|
+
[
|
|
220
|
+
'wrangler',
|
|
221
|
+
versions_cjs_namespaceObject.WRANGLER_VERSION
|
|
222
|
+
],
|
|
223
|
+
[
|
|
224
|
+
'zephyr-agent',
|
|
225
|
+
versions_cjs_namespaceObject.ZEPHYR_AGENT_VERSION
|
|
226
|
+
],
|
|
227
|
+
[
|
|
228
|
+
'zephyr-rspack-plugin',
|
|
229
|
+
versions_cjs_namespaceObject.ZEPHYR_RSPACK_PLUGIN_VERSION
|
|
230
|
+
]
|
|
231
|
+
]);
|
|
232
|
+
const strictEffectTrustPolicyExclusions = [
|
|
233
|
+
`effect@${versions_cjs_namespaceObject.EFFECT_VERSION}`,
|
|
234
|
+
`@effect/opentelemetry@${versions_cjs_namespaceObject.EFFECT_VERSION}`
|
|
235
|
+
];
|
|
236
|
+
function updateGeneratedToolingDependencies(packageJson) {
|
|
237
|
+
let changed = false;
|
|
238
|
+
for (const section of [
|
|
239
|
+
'dependencies',
|
|
240
|
+
'devDependencies',
|
|
241
|
+
'peerDependencies',
|
|
242
|
+
'optionalDependencies'
|
|
243
|
+
]){
|
|
244
|
+
const dependencies = packageJson[section];
|
|
245
|
+
if (!(!dependencies || 'object' != typeof dependencies || Array.isArray(dependencies))) {
|
|
246
|
+
for (const [packageName, version] of generatedToolingDependencyPins)if (Object.prototype.hasOwnProperty.call(dependencies, packageName) && dependencies[packageName] !== version) {
|
|
247
|
+
dependencies[packageName] = version;
|
|
248
|
+
changed = true;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return changed;
|
|
253
|
+
}
|
|
201
254
|
function normalizeStrictEffectApiMetadata(value) {
|
|
202
255
|
const api = value.api;
|
|
203
256
|
if (!api || 'object' != typeof api || Array.isArray(api)) return false;
|
|
@@ -263,6 +316,74 @@ function normalizeStrictEffectApiMetadata(value) {
|
|
|
263
316
|
}
|
|
264
317
|
return changed;
|
|
265
318
|
}
|
|
319
|
+
function replaceYamlLine(source, pattern, replacement) {
|
|
320
|
+
const updated = source.replace(pattern, replacement);
|
|
321
|
+
return {
|
|
322
|
+
source: updated,
|
|
323
|
+
changed: updated !== source
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function ensureYamlListItem(source, key, item) {
|
|
327
|
+
const itemLine = ` - '${item}'`;
|
|
328
|
+
const headerPattern = new RegExp(`^${key}:\\n(?:(?: - .+\\n)*)`, 'mu');
|
|
329
|
+
const existingItemPattern = new RegExp(`^ - '${item.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&')}'$`, 'mu');
|
|
330
|
+
if (existingItemPattern.test(source)) return {
|
|
331
|
+
source,
|
|
332
|
+
changed: false
|
|
333
|
+
};
|
|
334
|
+
const header = source.match(headerPattern);
|
|
335
|
+
if (header) return {
|
|
336
|
+
source: source.replace(headerPattern, `${header[0]}${itemLine}\n`),
|
|
337
|
+
changed: true
|
|
338
|
+
};
|
|
339
|
+
const block = `${key}:\n${itemLine}\n`;
|
|
340
|
+
const afterTrustPolicyIgnore = source.replace(/^(trustPolicyIgnoreAfter: .+\n)/mu, `$1${block}`);
|
|
341
|
+
if (afterTrustPolicyIgnore !== source) return {
|
|
342
|
+
source: afterTrustPolicyIgnore,
|
|
343
|
+
changed: true
|
|
344
|
+
};
|
|
345
|
+
return {
|
|
346
|
+
source: `${source.trimEnd()}\n${block}`,
|
|
347
|
+
changed: true
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
|
|
351
|
+
const workspaceFile = external_node_path_default().join(workspaceRoot, 'pnpm-workspace.yaml');
|
|
352
|
+
if (!external_node_fs_default().existsSync(workspaceFile)) return false;
|
|
353
|
+
let source = external_node_fs_default().readFileSync(workspaceFile, 'utf-8');
|
|
354
|
+
let changed = false;
|
|
355
|
+
const replacements = [
|
|
356
|
+
[
|
|
357
|
+
/^ {4}'@effect\/vitest>effect': .+$/mu,
|
|
358
|
+
` '@effect/vitest>effect': '${versions_cjs_namespaceObject.EFFECT_VERSION}'`
|
|
359
|
+
],
|
|
360
|
+
[
|
|
361
|
+
/^ {2}'@effect\/vitest': .+$/mu,
|
|
362
|
+
` '@effect/vitest': ${versions_cjs_namespaceObject.EFFECT_VITEST_VERSION}`
|
|
363
|
+
],
|
|
364
|
+
[
|
|
365
|
+
/^ {2}effect: .+$/mu,
|
|
366
|
+
` effect: ${versions_cjs_namespaceObject.EFFECT_VERSION}`
|
|
367
|
+
]
|
|
368
|
+
];
|
|
369
|
+
for (const [pattern, replacement] of replacements){
|
|
370
|
+
const result = replaceYamlLine(source, pattern, replacement);
|
|
371
|
+
source = result.source;
|
|
372
|
+
changed = result.changed || changed;
|
|
373
|
+
}
|
|
374
|
+
for (const item of strictEffectTrustPolicyExclusions){
|
|
375
|
+
const packageName = item.slice(0, item.lastIndexOf('@'));
|
|
376
|
+
const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
377
|
+
const currentVersion = replaceYamlLine(source, new RegExp(`^ {2}- '${escapedPackageName}@[^']+'$`, 'mu'), ` - '${item}'`);
|
|
378
|
+
source = currentVersion.source;
|
|
379
|
+
changed = currentVersion.changed || changed;
|
|
380
|
+
const trustPolicyExclude = ensureYamlListItem(source, 'trustPolicyExclude', item);
|
|
381
|
+
source = trustPolicyExclude.source;
|
|
382
|
+
changed = trustPolicyExclude.changed || changed;
|
|
383
|
+
}
|
|
384
|
+
if (changed) external_node_fs_default().writeFileSync(workspaceFile, source, 'utf-8');
|
|
385
|
+
return changed;
|
|
386
|
+
}
|
|
266
387
|
function updateUltramodernConfig(workspaceRoot, packageSource) {
|
|
267
388
|
const configPath = external_node_path_default().join(workspaceRoot, '.modernjs/ultramodern.json');
|
|
268
389
|
const config = readJsonFile(configPath);
|
|
@@ -344,8 +465,9 @@ function runMigrateStrictEffect(args, context) {
|
|
|
344
465
|
modern-js-create ultramodern migrate-strict-effect --version <version> [--skip-install]
|
|
345
466
|
|
|
346
467
|
Updates generated UltraModern package-source metadata, Modern package aliases,
|
|
347
|
-
direct Effect API topology metadata,
|
|
348
|
-
|
|
468
|
+
framework-owned toolchain pins, direct Effect API topology metadata, strict
|
|
469
|
+
Effect pnpm overrides/trust policy, and the pnpm lockfile. Source code still
|
|
470
|
+
has to pass pnpm api:check and pnpm contract:check.
|
|
349
471
|
`);
|
|
350
472
|
return 0;
|
|
351
473
|
}
|
|
@@ -363,9 +485,13 @@ workspaces. Source code still has to pass pnpm api:check and pnpm contract:check
|
|
|
363
485
|
config: './.modernjs/ultramodern.json'
|
|
364
486
|
};
|
|
365
487
|
}
|
|
366
|
-
|
|
488
|
+
const modernDependenciesChanged = updateModernDependencies(packageJson, packageSource);
|
|
489
|
+
const toolingDependenciesChanged = updateGeneratedToolingDependencies(packageJson);
|
|
490
|
+
const changed = modernDependenciesChanged || toolingDependenciesChanged;
|
|
491
|
+
if (changed) writeJsonFile(packageFile, packageJson);
|
|
367
492
|
else if ('package.json' === relativePackageFile) writeJsonFile(packageFile, packageJson);
|
|
368
493
|
}
|
|
494
|
+
updateGeneratedPnpmWorkspacePolicy(context.workspaceRoot);
|
|
369
495
|
if (!hasFlag(args, '--skip-install')) {
|
|
370
496
|
const status = runPnpmLockfileRefresh(context);
|
|
371
497
|
if (0 !== status) return status;
|
|
@@ -6,6 +6,7 @@ import { fileURLToPath } from "node:url";
|
|
|
6
6
|
import { resolveCreatePackageRoot } from "../create-package-root.js";
|
|
7
7
|
import { BLEEDINGDEV_PACKAGE_NAME_PREFIX, BLEEDINGDEV_PACKAGE_SCOPE, ULTRAMODERN_SINGLE_APP_MODERN_PACKAGES, ULTRAMODERN_WORKSPACE_MODERN_PACKAGES, WORKSPACE_PACKAGE_VERSION, modernPackageSpecifier } from "../ultramodern-package-source.js";
|
|
8
8
|
import { validateModuleFederationTypes } from "../ultramodern-workspace/mf-validation.js";
|
|
9
|
+
import { EFFECT_TSGO_VERSION, EFFECT_VERSION, EFFECT_VITEST_VERSION, OXFMT_VERSION, OXLINT_VERSION, TYPESCRIPT_NATIVE_PREVIEW_VERSION, WRANGLER_VERSION, ZEPHYR_AGENT_VERSION, ZEPHYR_RSPACK_PLUGIN_VERSION } from "../ultramodern-workspace/versions.js";
|
|
9
10
|
import { createWorkspaceValidationScript } from "../ultramodern-workspace/workspace-scripts.js";
|
|
10
11
|
import { readUltramodernConfig, workspaceAppsFromToolingConfig } from "./config.js";
|
|
11
12
|
const commands_dirname = node_path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -151,6 +152,58 @@ function updateModernDependencies(packageJson, packageSource) {
|
|
|
151
152
|
}
|
|
152
153
|
return changed;
|
|
153
154
|
}
|
|
155
|
+
const generatedToolingDependencyPins = new Map([
|
|
156
|
+
[
|
|
157
|
+
'@effect/tsgo',
|
|
158
|
+
EFFECT_TSGO_VERSION
|
|
159
|
+
],
|
|
160
|
+
[
|
|
161
|
+
"@typescript/native-preview",
|
|
162
|
+
TYPESCRIPT_NATIVE_PREVIEW_VERSION
|
|
163
|
+
],
|
|
164
|
+
[
|
|
165
|
+
'oxfmt',
|
|
166
|
+
OXFMT_VERSION
|
|
167
|
+
],
|
|
168
|
+
[
|
|
169
|
+
'oxlint',
|
|
170
|
+
OXLINT_VERSION
|
|
171
|
+
],
|
|
172
|
+
[
|
|
173
|
+
'wrangler',
|
|
174
|
+
WRANGLER_VERSION
|
|
175
|
+
],
|
|
176
|
+
[
|
|
177
|
+
'zephyr-agent',
|
|
178
|
+
ZEPHYR_AGENT_VERSION
|
|
179
|
+
],
|
|
180
|
+
[
|
|
181
|
+
'zephyr-rspack-plugin',
|
|
182
|
+
ZEPHYR_RSPACK_PLUGIN_VERSION
|
|
183
|
+
]
|
|
184
|
+
]);
|
|
185
|
+
const strictEffectTrustPolicyExclusions = [
|
|
186
|
+
`effect@${EFFECT_VERSION}`,
|
|
187
|
+
`@effect/opentelemetry@${EFFECT_VERSION}`
|
|
188
|
+
];
|
|
189
|
+
function updateGeneratedToolingDependencies(packageJson) {
|
|
190
|
+
let changed = false;
|
|
191
|
+
for (const section of [
|
|
192
|
+
'dependencies',
|
|
193
|
+
'devDependencies',
|
|
194
|
+
'peerDependencies',
|
|
195
|
+
'optionalDependencies'
|
|
196
|
+
]){
|
|
197
|
+
const dependencies = packageJson[section];
|
|
198
|
+
if (!(!dependencies || 'object' != typeof dependencies || Array.isArray(dependencies))) {
|
|
199
|
+
for (const [packageName, version] of generatedToolingDependencyPins)if (Object.prototype.hasOwnProperty.call(dependencies, packageName) && dependencies[packageName] !== version) {
|
|
200
|
+
dependencies[packageName] = version;
|
|
201
|
+
changed = true;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return changed;
|
|
206
|
+
}
|
|
154
207
|
function normalizeStrictEffectApiMetadata(value) {
|
|
155
208
|
const api = value.api;
|
|
156
209
|
if (!api || 'object' != typeof api || Array.isArray(api)) return false;
|
|
@@ -216,6 +269,74 @@ function normalizeStrictEffectApiMetadata(value) {
|
|
|
216
269
|
}
|
|
217
270
|
return changed;
|
|
218
271
|
}
|
|
272
|
+
function replaceYamlLine(source, pattern, replacement) {
|
|
273
|
+
const updated = source.replace(pattern, replacement);
|
|
274
|
+
return {
|
|
275
|
+
source: updated,
|
|
276
|
+
changed: updated !== source
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
function ensureYamlListItem(source, key, item) {
|
|
280
|
+
const itemLine = ` - '${item}'`;
|
|
281
|
+
const headerPattern = new RegExp(`^${key}:\\n(?:(?: - .+\\n)*)`, 'mu');
|
|
282
|
+
const existingItemPattern = new RegExp(`^ - '${item.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&')}'$`, 'mu');
|
|
283
|
+
if (existingItemPattern.test(source)) return {
|
|
284
|
+
source,
|
|
285
|
+
changed: false
|
|
286
|
+
};
|
|
287
|
+
const header = source.match(headerPattern);
|
|
288
|
+
if (header) return {
|
|
289
|
+
source: source.replace(headerPattern, `${header[0]}${itemLine}\n`),
|
|
290
|
+
changed: true
|
|
291
|
+
};
|
|
292
|
+
const block = `${key}:\n${itemLine}\n`;
|
|
293
|
+
const afterTrustPolicyIgnore = source.replace(/^(trustPolicyIgnoreAfter: .+\n)/mu, `$1${block}`);
|
|
294
|
+
if (afterTrustPolicyIgnore !== source) return {
|
|
295
|
+
source: afterTrustPolicyIgnore,
|
|
296
|
+
changed: true
|
|
297
|
+
};
|
|
298
|
+
return {
|
|
299
|
+
source: `${source.trimEnd()}\n${block}`,
|
|
300
|
+
changed: true
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
|
|
304
|
+
const workspaceFile = node_path.join(workspaceRoot, 'pnpm-workspace.yaml');
|
|
305
|
+
if (!node_fs.existsSync(workspaceFile)) return false;
|
|
306
|
+
let source = node_fs.readFileSync(workspaceFile, 'utf-8');
|
|
307
|
+
let changed = false;
|
|
308
|
+
const replacements = [
|
|
309
|
+
[
|
|
310
|
+
/^ {4}'@effect\/vitest>effect': .+$/mu,
|
|
311
|
+
` '@effect/vitest>effect': '${EFFECT_VERSION}'`
|
|
312
|
+
],
|
|
313
|
+
[
|
|
314
|
+
/^ {2}'@effect\/vitest': .+$/mu,
|
|
315
|
+
` '@effect/vitest': ${EFFECT_VITEST_VERSION}`
|
|
316
|
+
],
|
|
317
|
+
[
|
|
318
|
+
/^ {2}effect: .+$/mu,
|
|
319
|
+
` effect: ${EFFECT_VERSION}`
|
|
320
|
+
]
|
|
321
|
+
];
|
|
322
|
+
for (const [pattern, replacement] of replacements){
|
|
323
|
+
const result = replaceYamlLine(source, pattern, replacement);
|
|
324
|
+
source = result.source;
|
|
325
|
+
changed = result.changed || changed;
|
|
326
|
+
}
|
|
327
|
+
for (const item of strictEffectTrustPolicyExclusions){
|
|
328
|
+
const packageName = item.slice(0, item.lastIndexOf('@'));
|
|
329
|
+
const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
330
|
+
const currentVersion = replaceYamlLine(source, new RegExp(`^ {2}- '${escapedPackageName}@[^']+'$`, 'mu'), ` - '${item}'`);
|
|
331
|
+
source = currentVersion.source;
|
|
332
|
+
changed = currentVersion.changed || changed;
|
|
333
|
+
const trustPolicyExclude = ensureYamlListItem(source, 'trustPolicyExclude', item);
|
|
334
|
+
source = trustPolicyExclude.source;
|
|
335
|
+
changed = trustPolicyExclude.changed || changed;
|
|
336
|
+
}
|
|
337
|
+
if (changed) node_fs.writeFileSync(workspaceFile, source, 'utf-8');
|
|
338
|
+
return changed;
|
|
339
|
+
}
|
|
219
340
|
function updateUltramodernConfig(workspaceRoot, packageSource) {
|
|
220
341
|
const configPath = node_path.join(workspaceRoot, '.modernjs/ultramodern.json');
|
|
221
342
|
const config = readJsonFile(configPath);
|
|
@@ -297,8 +418,9 @@ function runMigrateStrictEffect(args, context) {
|
|
|
297
418
|
modern-js-create ultramodern migrate-strict-effect --version <version> [--skip-install]
|
|
298
419
|
|
|
299
420
|
Updates generated UltraModern package-source metadata, Modern package aliases,
|
|
300
|
-
direct Effect API topology metadata,
|
|
301
|
-
|
|
421
|
+
framework-owned toolchain pins, direct Effect API topology metadata, strict
|
|
422
|
+
Effect pnpm overrides/trust policy, and the pnpm lockfile. Source code still
|
|
423
|
+
has to pass pnpm api:check and pnpm contract:check.
|
|
302
424
|
`);
|
|
303
425
|
return 0;
|
|
304
426
|
}
|
|
@@ -316,9 +438,13 @@ workspaces. Source code still has to pass pnpm api:check and pnpm contract:check
|
|
|
316
438
|
config: './.modernjs/ultramodern.json'
|
|
317
439
|
};
|
|
318
440
|
}
|
|
319
|
-
|
|
441
|
+
const modernDependenciesChanged = updateModernDependencies(packageJson, packageSource);
|
|
442
|
+
const toolingDependenciesChanged = updateGeneratedToolingDependencies(packageJson);
|
|
443
|
+
const changed = modernDependenciesChanged || toolingDependenciesChanged;
|
|
444
|
+
if (changed) writeJsonFile(packageFile, packageJson);
|
|
320
445
|
else if ('package.json' === relativePackageFile) writeJsonFile(packageFile, packageJson);
|
|
321
446
|
}
|
|
447
|
+
updateGeneratedPnpmWorkspacePolicy(context.workspaceRoot);
|
|
322
448
|
if (!hasFlag(args, '--skip-install')) {
|
|
323
449
|
const status = runPnpmLockfileRefresh(context);
|
|
324
450
|
if (0 !== status) return status;
|
|
@@ -7,6 +7,7 @@ import { fileURLToPath } from "node:url";
|
|
|
7
7
|
import { resolveCreatePackageRoot } from "../create-package-root.js";
|
|
8
8
|
import { BLEEDINGDEV_PACKAGE_NAME_PREFIX, BLEEDINGDEV_PACKAGE_SCOPE, ULTRAMODERN_SINGLE_APP_MODERN_PACKAGES, ULTRAMODERN_WORKSPACE_MODERN_PACKAGES, WORKSPACE_PACKAGE_VERSION, modernPackageSpecifier } from "../ultramodern-package-source.js";
|
|
9
9
|
import { validateModuleFederationTypes } from "../ultramodern-workspace/mf-validation.js";
|
|
10
|
+
import { EFFECT_TSGO_VERSION, EFFECT_VERSION, EFFECT_VITEST_VERSION, OXFMT_VERSION, OXLINT_VERSION, TYPESCRIPT_NATIVE_PREVIEW_VERSION, WRANGLER_VERSION, ZEPHYR_AGENT_VERSION, ZEPHYR_RSPACK_PLUGIN_VERSION } from "../ultramodern-workspace/versions.js";
|
|
10
11
|
import { createWorkspaceValidationScript } from "../ultramodern-workspace/workspace-scripts.js";
|
|
11
12
|
import { readUltramodernConfig, workspaceAppsFromToolingConfig } from "./config.js";
|
|
12
13
|
const commands_dirname = node_path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -152,6 +153,58 @@ function updateModernDependencies(packageJson, packageSource) {
|
|
|
152
153
|
}
|
|
153
154
|
return changed;
|
|
154
155
|
}
|
|
156
|
+
const generatedToolingDependencyPins = new Map([
|
|
157
|
+
[
|
|
158
|
+
'@effect/tsgo',
|
|
159
|
+
EFFECT_TSGO_VERSION
|
|
160
|
+
],
|
|
161
|
+
[
|
|
162
|
+
"@typescript/native-preview",
|
|
163
|
+
TYPESCRIPT_NATIVE_PREVIEW_VERSION
|
|
164
|
+
],
|
|
165
|
+
[
|
|
166
|
+
'oxfmt',
|
|
167
|
+
OXFMT_VERSION
|
|
168
|
+
],
|
|
169
|
+
[
|
|
170
|
+
'oxlint',
|
|
171
|
+
OXLINT_VERSION
|
|
172
|
+
],
|
|
173
|
+
[
|
|
174
|
+
'wrangler',
|
|
175
|
+
WRANGLER_VERSION
|
|
176
|
+
],
|
|
177
|
+
[
|
|
178
|
+
'zephyr-agent',
|
|
179
|
+
ZEPHYR_AGENT_VERSION
|
|
180
|
+
],
|
|
181
|
+
[
|
|
182
|
+
'zephyr-rspack-plugin',
|
|
183
|
+
ZEPHYR_RSPACK_PLUGIN_VERSION
|
|
184
|
+
]
|
|
185
|
+
]);
|
|
186
|
+
const strictEffectTrustPolicyExclusions = [
|
|
187
|
+
`effect@${EFFECT_VERSION}`,
|
|
188
|
+
`@effect/opentelemetry@${EFFECT_VERSION}`
|
|
189
|
+
];
|
|
190
|
+
function updateGeneratedToolingDependencies(packageJson) {
|
|
191
|
+
let changed = false;
|
|
192
|
+
for (const section of [
|
|
193
|
+
'dependencies',
|
|
194
|
+
'devDependencies',
|
|
195
|
+
'peerDependencies',
|
|
196
|
+
'optionalDependencies'
|
|
197
|
+
]){
|
|
198
|
+
const dependencies = packageJson[section];
|
|
199
|
+
if (!(!dependencies || 'object' != typeof dependencies || Array.isArray(dependencies))) {
|
|
200
|
+
for (const [packageName, version] of generatedToolingDependencyPins)if (Object.prototype.hasOwnProperty.call(dependencies, packageName) && dependencies[packageName] !== version) {
|
|
201
|
+
dependencies[packageName] = version;
|
|
202
|
+
changed = true;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return changed;
|
|
207
|
+
}
|
|
155
208
|
function normalizeStrictEffectApiMetadata(value) {
|
|
156
209
|
const api = value.api;
|
|
157
210
|
if (!api || 'object' != typeof api || Array.isArray(api)) return false;
|
|
@@ -217,6 +270,74 @@ function normalizeStrictEffectApiMetadata(value) {
|
|
|
217
270
|
}
|
|
218
271
|
return changed;
|
|
219
272
|
}
|
|
273
|
+
function replaceYamlLine(source, pattern, replacement) {
|
|
274
|
+
const updated = source.replace(pattern, replacement);
|
|
275
|
+
return {
|
|
276
|
+
source: updated,
|
|
277
|
+
changed: updated !== source
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function ensureYamlListItem(source, key, item) {
|
|
281
|
+
const itemLine = ` - '${item}'`;
|
|
282
|
+
const headerPattern = new RegExp(`^${key}:\\n(?:(?: - .+\\n)*)`, 'mu');
|
|
283
|
+
const existingItemPattern = new RegExp(`^ - '${item.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&')}'$`, 'mu');
|
|
284
|
+
if (existingItemPattern.test(source)) return {
|
|
285
|
+
source,
|
|
286
|
+
changed: false
|
|
287
|
+
};
|
|
288
|
+
const header = source.match(headerPattern);
|
|
289
|
+
if (header) return {
|
|
290
|
+
source: source.replace(headerPattern, `${header[0]}${itemLine}\n`),
|
|
291
|
+
changed: true
|
|
292
|
+
};
|
|
293
|
+
const block = `${key}:\n${itemLine}\n`;
|
|
294
|
+
const afterTrustPolicyIgnore = source.replace(/^(trustPolicyIgnoreAfter: .+\n)/mu, `$1${block}`);
|
|
295
|
+
if (afterTrustPolicyIgnore !== source) return {
|
|
296
|
+
source: afterTrustPolicyIgnore,
|
|
297
|
+
changed: true
|
|
298
|
+
};
|
|
299
|
+
return {
|
|
300
|
+
source: `${source.trimEnd()}\n${block}`,
|
|
301
|
+
changed: true
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
|
|
305
|
+
const workspaceFile = node_path.join(workspaceRoot, 'pnpm-workspace.yaml');
|
|
306
|
+
if (!node_fs.existsSync(workspaceFile)) return false;
|
|
307
|
+
let source = node_fs.readFileSync(workspaceFile, 'utf-8');
|
|
308
|
+
let changed = false;
|
|
309
|
+
const replacements = [
|
|
310
|
+
[
|
|
311
|
+
/^ {4}'@effect\/vitest>effect': .+$/mu,
|
|
312
|
+
` '@effect/vitest>effect': '${EFFECT_VERSION}'`
|
|
313
|
+
],
|
|
314
|
+
[
|
|
315
|
+
/^ {2}'@effect\/vitest': .+$/mu,
|
|
316
|
+
` '@effect/vitest': ${EFFECT_VITEST_VERSION}`
|
|
317
|
+
],
|
|
318
|
+
[
|
|
319
|
+
/^ {2}effect: .+$/mu,
|
|
320
|
+
` effect: ${EFFECT_VERSION}`
|
|
321
|
+
]
|
|
322
|
+
];
|
|
323
|
+
for (const [pattern, replacement] of replacements){
|
|
324
|
+
const result = replaceYamlLine(source, pattern, replacement);
|
|
325
|
+
source = result.source;
|
|
326
|
+
changed = result.changed || changed;
|
|
327
|
+
}
|
|
328
|
+
for (const item of strictEffectTrustPolicyExclusions){
|
|
329
|
+
const packageName = item.slice(0, item.lastIndexOf('@'));
|
|
330
|
+
const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
331
|
+
const currentVersion = replaceYamlLine(source, new RegExp(`^ {2}- '${escapedPackageName}@[^']+'$`, 'mu'), ` - '${item}'`);
|
|
332
|
+
source = currentVersion.source;
|
|
333
|
+
changed = currentVersion.changed || changed;
|
|
334
|
+
const trustPolicyExclude = ensureYamlListItem(source, 'trustPolicyExclude', item);
|
|
335
|
+
source = trustPolicyExclude.source;
|
|
336
|
+
changed = trustPolicyExclude.changed || changed;
|
|
337
|
+
}
|
|
338
|
+
if (changed) node_fs.writeFileSync(workspaceFile, source, 'utf-8');
|
|
339
|
+
return changed;
|
|
340
|
+
}
|
|
220
341
|
function updateUltramodernConfig(workspaceRoot, packageSource) {
|
|
221
342
|
const configPath = node_path.join(workspaceRoot, '.modernjs/ultramodern.json');
|
|
222
343
|
const config = readJsonFile(configPath);
|
|
@@ -298,8 +419,9 @@ function runMigrateStrictEffect(args, context) {
|
|
|
298
419
|
modern-js-create ultramodern migrate-strict-effect --version <version> [--skip-install]
|
|
299
420
|
|
|
300
421
|
Updates generated UltraModern package-source metadata, Modern package aliases,
|
|
301
|
-
direct Effect API topology metadata,
|
|
302
|
-
|
|
422
|
+
framework-owned toolchain pins, direct Effect API topology metadata, strict
|
|
423
|
+
Effect pnpm overrides/trust policy, and the pnpm lockfile. Source code still
|
|
424
|
+
has to pass pnpm api:check and pnpm contract:check.
|
|
303
425
|
`);
|
|
304
426
|
return 0;
|
|
305
427
|
}
|
|
@@ -317,9 +439,13 @@ workspaces. Source code still has to pass pnpm api:check and pnpm contract:check
|
|
|
317
439
|
config: './.modernjs/ultramodern.json'
|
|
318
440
|
};
|
|
319
441
|
}
|
|
320
|
-
|
|
442
|
+
const modernDependenciesChanged = updateModernDependencies(packageJson, packageSource);
|
|
443
|
+
const toolingDependenciesChanged = updateGeneratedToolingDependencies(packageJson);
|
|
444
|
+
const changed = modernDependenciesChanged || toolingDependenciesChanged;
|
|
445
|
+
if (changed) writeJsonFile(packageFile, packageJson);
|
|
321
446
|
else if ('package.json' === relativePackageFile) writeJsonFile(packageFile, packageJson);
|
|
322
447
|
}
|
|
448
|
+
updateGeneratedPnpmWorkspacePolicy(context.workspaceRoot);
|
|
323
449
|
if (!hasFlag(args, '--skip-install')) {
|
|
324
450
|
const status = runPnpmLockfileRefresh(context);
|
|
325
451
|
if (0 !== status) return status;
|
package/package.json
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"engines": {
|
|
22
22
|
"node": ">=20"
|
|
23
23
|
},
|
|
24
|
-
"version": "3.5.0-ultramodern.
|
|
24
|
+
"version": "3.5.0-ultramodern.4",
|
|
25
25
|
"types": "./dist/types/index.d.ts",
|
|
26
26
|
"main": "./dist/esm-node/index.js",
|
|
27
27
|
"bin": {
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"@modern-js/codesmith": "2.6.9",
|
|
78
78
|
"oxfmt": "0.56.0",
|
|
79
79
|
"ultracite": "7.8.3",
|
|
80
|
-
"@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.5.0-ultramodern.
|
|
80
|
+
"@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.5.0-ultramodern.4"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
83
|
"@rslib/core": "0.23.1",
|
|
@@ -99,6 +99,6 @@
|
|
|
99
99
|
"test": "rm -rf dist && rslib build -c rslibconfig.mts && rstest --passWithNoTests"
|
|
100
100
|
},
|
|
101
101
|
"ultramodern": {
|
|
102
|
-
"frameworkVersion": "3.5.0-ultramodern.
|
|
102
|
+
"frameworkVersion": "3.5.0-ultramodern.4"
|
|
103
103
|
}
|
|
104
104
|
}
|
|
@@ -169,19 +169,23 @@ in API modules.
|
|
|
169
169
|
Generated pnpm overrides pin the framework-compatible Effect cohort. Keep
|
|
170
170
|
`effect` and `@effect/vitest` aligned with `pnpm-workspace.yaml`; do not add
|
|
171
171
|
new direct package-level Effect versions unless the whole UltraModern cohort is
|
|
172
|
-
upgraded.
|
|
172
|
+
upgraded. The generated pnpm trust policy intentionally excludes the matching
|
|
173
|
+
`effect` and `@effect/opentelemetry` cohort packages from no-downgrade checks
|
|
174
|
+
while Effect's beta publishes move from trusted-publisher metadata to
|
|
175
|
+
provenance attestations.
|
|
173
176
|
|
|
174
177
|
For older generated workspaces, run the framework migration command first:
|
|
175
178
|
|
|
176
179
|
```bash
|
|
177
|
-
pnpm dlx @bleedingdev/modern-js-create@3.5.0-ultramodern.
|
|
178
|
-
migrate-strict-effect --version 3.5.0-ultramodern.
|
|
180
|
+
pnpm dlx @bleedingdev/modern-js-create@3.5.0-ultramodern.4 ultramodern \
|
|
181
|
+
migrate-strict-effect --version 3.5.0-ultramodern.4
|
|
179
182
|
pnpm api:check
|
|
180
183
|
pnpm contract:check
|
|
181
184
|
```
|
|
182
185
|
|
|
183
186
|
The command updates generated package-source metadata, Modern package aliases,
|
|
184
|
-
direct API topology metadata,
|
|
187
|
+
framework-owned toolchain pins, direct API topology metadata, strict Effect pnpm
|
|
188
|
+
overrides/trust policy, and the lockfile. Remaining failures are source
|
|
185
189
|
migration work; fix the owning API files instead of adding compatibility shims.
|
|
186
190
|
|
|
187
191
|
## Troubleshooting
|
|
@@ -24,6 +24,9 @@ minimumReleaseAgeExclude:
|
|
|
24
24
|
- 'ts-checker-rspack-plugin'
|
|
25
25
|
trustPolicy: no-downgrade
|
|
26
26
|
trustPolicyIgnoreAfter: 1440
|
|
27
|
+
trustPolicyExclude:
|
|
28
|
+
- 'effect@{{effectVersion}}'
|
|
29
|
+
- '@effect/opentelemetry@{{effectVersion}}'
|
|
27
30
|
blockExoticSubdeps: true
|
|
28
31
|
engineStrict: true
|
|
29
32
|
pmOnFail: error
|