@bleedingdev/modern-js-create 3.5.0-ultramodern.27 → 3.5.0-ultramodern.29
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/dist/cjs/ultramodern-tooling/commands.cjs +497 -155
- package/dist/cjs/ultramodern-tooling/config.cjs +149 -8
- package/dist/cjs/ultramodern-workspace/add-vertical.cjs +25 -0
- package/dist/cjs/ultramodern-workspace/api.cjs +44 -0
- package/dist/cjs/ultramodern-workspace/backend-federation.cjs +282 -0
- package/dist/cjs/ultramodern-workspace/contracts.cjs +24 -8
- package/dist/cjs/ultramodern-workspace/delivery-unit-sync.cjs +157 -0
- package/dist/cjs/ultramodern-workspace/delivery-unit.cjs +88 -0
- package/dist/cjs/ultramodern-workspace/descriptors.cjs +24 -0
- package/dist/cjs/ultramodern-workspace/module-federation.cjs +122 -44
- package/dist/cjs/ultramodern-workspace/package-json.cjs +11 -34
- package/dist/cjs/ultramodern-workspace/pnpm-workspace-policy-plan.cjs +166 -0
- package/dist/cjs/ultramodern-workspace/tooling-command-catalog.cjs +153 -0
- package/dist/cjs/ultramodern-workspace/workspace-script-plan.cjs +175 -0
- package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +43 -62
- package/dist/cjs/ultramodern-workspace/workspace-validation-contract.cjs +97 -0
- package/dist/cjs/ultramodern-workspace/write-workspace.cjs +9 -3
- package/dist/cjs/ultramodern-workspace/zerops.cjs +100 -0
- package/dist/esm/ultramodern-tooling/commands.js +500 -158
- package/dist/esm/ultramodern-tooling/config.js +144 -9
- package/dist/esm/ultramodern-workspace/add-vertical.js +26 -1
- package/dist/esm/ultramodern-workspace/api.js +43 -2
- package/dist/esm/ultramodern-workspace/backend-federation.js +217 -0
- package/dist/esm/ultramodern-workspace/contracts.js +24 -8
- package/dist/esm/ultramodern-workspace/delivery-unit-sync.js +108 -0
- package/dist/esm/ultramodern-workspace/delivery-unit.js +31 -0
- package/dist/esm/ultramodern-workspace/descriptors.js +13 -1
- package/dist/esm/ultramodern-workspace/module-federation.js +121 -36
- package/dist/esm/ultramodern-workspace/package-json.js +11 -31
- package/dist/esm/ultramodern-workspace/pnpm-workspace-policy-plan.js +113 -0
- package/dist/esm/ultramodern-workspace/tooling-command-catalog.js +100 -0
- package/dist/esm/ultramodern-workspace/workspace-script-plan.js +110 -0
- package/dist/esm/ultramodern-workspace/workspace-scripts.js +35 -63
- package/dist/esm/ultramodern-workspace/workspace-validation-contract.js +59 -0
- package/dist/esm/ultramodern-workspace/write-workspace.js +11 -5
- package/dist/esm/ultramodern-workspace/zerops.js +62 -0
- package/dist/esm-node/ultramodern-tooling/commands.js +500 -158
- package/dist/esm-node/ultramodern-tooling/config.js +144 -9
- package/dist/esm-node/ultramodern-workspace/add-vertical.js +26 -1
- package/dist/esm-node/ultramodern-workspace/api.js +43 -2
- package/dist/esm-node/ultramodern-workspace/backend-federation.js +218 -0
- package/dist/esm-node/ultramodern-workspace/contracts.js +24 -8
- package/dist/esm-node/ultramodern-workspace/delivery-unit-sync.js +109 -0
- package/dist/esm-node/ultramodern-workspace/delivery-unit.js +32 -0
- package/dist/esm-node/ultramodern-workspace/descriptors.js +13 -1
- package/dist/esm-node/ultramodern-workspace/module-federation.js +121 -36
- package/dist/esm-node/ultramodern-workspace/package-json.js +11 -31
- package/dist/esm-node/ultramodern-workspace/pnpm-workspace-policy-plan.js +114 -0
- package/dist/esm-node/ultramodern-workspace/tooling-command-catalog.js +101 -0
- package/dist/esm-node/ultramodern-workspace/workspace-script-plan.js +111 -0
- package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +35 -63
- package/dist/esm-node/ultramodern-workspace/workspace-validation-contract.js +60 -0
- package/dist/esm-node/ultramodern-workspace/write-workspace.js +11 -5
- package/dist/esm-node/ultramodern-workspace/zerops.js +63 -0
- package/dist/types/ultramodern-tooling/config.d.ts +6 -0
- package/dist/types/ultramodern-workspace/api.d.ts +1 -0
- package/dist/types/ultramodern-workspace/backend-federation.d.ts +11 -0
- package/dist/types/ultramodern-workspace/contracts.d.ts +1 -1
- package/dist/types/ultramodern-workspace/delivery-unit-sync.d.ts +6 -0
- package/dist/types/ultramodern-workspace/delivery-unit.d.ts +27 -0
- package/dist/types/ultramodern-workspace/descriptors.d.ts +4 -0
- package/dist/types/ultramodern-workspace/module-federation.d.ts +4 -9
- package/dist/types/ultramodern-workspace/package-json.d.ts +0 -1
- package/dist/types/ultramodern-workspace/pnpm-workspace-policy-plan.d.ts +39 -0
- package/dist/types/ultramodern-workspace/tooling-command-catalog.d.ts +18 -0
- package/dist/types/ultramodern-workspace/workspace-script-plan.d.ts +72 -0
- package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +3 -0
- package/dist/types/ultramodern-workspace/workspace-validation-contract.d.ts +42 -0
- package/dist/types/ultramodern-workspace/zerops.d.ts +2 -0
- package/package.json +3 -3
- package/template-workspace/.gitignore.handlebars +1 -0
- package/template-workspace/scripts/bootstrap-agent-skills.mjs +11 -3
- package/templates/workspace-scripts/check-ultramodern-api-boundaries.mts +40 -2
- package/templates/workspace-scripts/generate-node-backend-federation.mjs +270 -0
- package/templates/workspace-scripts/materialize-zerops-runtime.mjs +448 -0
- package/templates/workspace-scripts/proof-cloudflare-version.mjs +234 -8
- package/templates/workspace-scripts/proof-node-backend-federation.mjs +729 -0
- package/templates/workspace-scripts/ultramodern-cloudflare-proof.mjs +188 -2
- package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +322 -8
|
@@ -53,28 +53,30 @@ 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 app_files_cjs_namespaceObject = require("../ultramodern-workspace/app-files.cjs");
|
|
56
|
+
const backend_federation_cjs_namespaceObject = require("../ultramodern-workspace/backend-federation.cjs");
|
|
57
|
+
const delivery_unit_sync_cjs_namespaceObject = require("../ultramodern-workspace/delivery-unit-sync.cjs");
|
|
56
58
|
const mf_validation_cjs_namespaceObject = require("../ultramodern-workspace/mf-validation.cjs");
|
|
57
59
|
const module_federation_cjs_namespaceObject = require("../ultramodern-workspace/module-federation.cjs");
|
|
58
60
|
const package_json_cjs_namespaceObject = require("../ultramodern-workspace/package-json.cjs");
|
|
61
|
+
const tooling_command_catalog_cjs_namespaceObject = require("../ultramodern-workspace/tooling-command-catalog.cjs");
|
|
59
62
|
const versions_cjs_namespaceObject = require("../ultramodern-workspace/versions.cjs");
|
|
63
|
+
const workspace_script_plan_cjs_namespaceObject = require("../ultramodern-workspace/workspace-script-plan.cjs");
|
|
60
64
|
const workspace_scripts_cjs_namespaceObject = require("../ultramodern-workspace/workspace-scripts.cjs");
|
|
65
|
+
const zerops_cjs_namespaceObject = require("../ultramodern-workspace/zerops.cjs");
|
|
61
66
|
const external_config_cjs_namespaceObject = require("./config.cjs");
|
|
62
67
|
const commands_dirname = external_node_path_default().dirname((0, external_node_url_namespaceObject.fileURLToPath)(__rslib_import_meta_url__));
|
|
63
68
|
const createPackageRoot = (0, external_create_package_root_cjs_namespaceObject.resolveCreatePackageRoot)(commands_dirname);
|
|
64
69
|
function printHelp() {
|
|
70
|
+
const commands = [
|
|
71
|
+
...(0, tooling_command_catalog_cjs_namespaceObject.generatedToolingCommandList)().map((command)=>` ${command}`),
|
|
72
|
+
' skills install',
|
|
73
|
+
' skills check'
|
|
74
|
+
].join('\n');
|
|
65
75
|
process.stdout.write(`Usage:
|
|
66
76
|
modern-js-create ultramodern <command> [args]
|
|
67
77
|
|
|
68
78
|
Commands:
|
|
69
|
-
|
|
70
|
-
typecheck
|
|
71
|
-
mf-types
|
|
72
|
-
migrate-strict-effect
|
|
73
|
-
public-surface
|
|
74
|
-
cloudflare-proof
|
|
75
|
-
performance-readiness
|
|
76
|
-
skills install
|
|
77
|
-
skills check
|
|
79
|
+
${commands}
|
|
78
80
|
`);
|
|
79
81
|
}
|
|
80
82
|
function spawnNodeScript(relativeScriptPath, args, context, options = {}) {
|
|
@@ -93,6 +95,13 @@ function spawnNodeScript(relativeScriptPath, args, context, options = {}) {
|
|
|
93
95
|
if (result.error) throw result.error;
|
|
94
96
|
return result.status ?? 1;
|
|
95
97
|
}
|
|
98
|
+
function runTemplateBackedToolingCommand(command, args, context) {
|
|
99
|
+
const toolingCommand = tooling_command_catalog_cjs_namespaceObject.generatedToolingCommands.find((candidate)=>candidate.command === command);
|
|
100
|
+
if (!toolingCommand?.templatePath) return;
|
|
101
|
+
return spawnNodeScript(toolingCommand.templatePath, args, context, {
|
|
102
|
+
cwd: 'invocation' === toolingCommand.cwd ? context.invocationCwd : context.workspaceRoot
|
|
103
|
+
});
|
|
104
|
+
}
|
|
96
105
|
function runRenderedModule(source, context) {
|
|
97
106
|
const tempDir = external_node_fs_default().mkdtempSync(external_node_path_default().join(external_node_os_default().tmpdir(), 'ultramodern-tool-'));
|
|
98
107
|
const tempFile = external_node_path_default().join(tempDir, 'command.mjs');
|
|
@@ -139,11 +148,45 @@ const modernPackageNames = new Set([
|
|
|
139
148
|
...external_ultramodern_package_source_cjs_namespaceObject.ULTRAMODERN_SINGLE_APP_MODERN_PACKAGES,
|
|
140
149
|
...external_ultramodern_package_source_cjs_namespaceObject.ULTRAMODERN_WORKSPACE_MODERN_PACKAGES
|
|
141
150
|
]);
|
|
151
|
+
function createMigrationIo(workspaceRoot, dryRun) {
|
|
152
|
+
const plan = [];
|
|
153
|
+
const rel = (p)=>(external_node_path_default().relative(workspaceRoot, p) || external_node_path_default().basename(p)).split(external_node_path_default().sep).join('/');
|
|
154
|
+
return {
|
|
155
|
+
workspaceRoot,
|
|
156
|
+
dryRun,
|
|
157
|
+
plan,
|
|
158
|
+
write (filePath, content) {
|
|
159
|
+
if (external_node_fs_default().existsSync(filePath) && external_node_fs_default().readFileSync(filePath, 'utf-8') === content) return false;
|
|
160
|
+
if (dryRun) {
|
|
161
|
+
plan.push(`[dry-run] would write ${rel(filePath)}`);
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
external_node_fs_default().mkdirSync(external_node_path_default().dirname(filePath), {
|
|
165
|
+
recursive: true
|
|
166
|
+
});
|
|
167
|
+
external_node_fs_default().writeFileSync(filePath, content, 'utf-8');
|
|
168
|
+
return true;
|
|
169
|
+
},
|
|
170
|
+
remove (filePath) {
|
|
171
|
+
if (!external_node_fs_default().existsSync(filePath)) return false;
|
|
172
|
+
if (dryRun) {
|
|
173
|
+
plan.push(`[dry-run] would delete ${rel(filePath)}`);
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
external_node_fs_default().rmSync(filePath);
|
|
177
|
+
return true;
|
|
178
|
+
},
|
|
179
|
+
log (message) {
|
|
180
|
+
if (dryRun) plan.push(`[dry-run] ${message}`);
|
|
181
|
+
else process.stdout.write(`[ultramodern] ${message}\n`);
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
}
|
|
142
185
|
function readJsonFile(filePath) {
|
|
143
186
|
return JSON.parse(external_node_fs_default().readFileSync(filePath, 'utf-8'));
|
|
144
187
|
}
|
|
145
|
-
function writeJsonFile(filePath, value) {
|
|
146
|
-
|
|
188
|
+
function writeJsonFile(io, filePath, value) {
|
|
189
|
+
return io.write(filePath, `${JSON.stringify(value, null, 2)}\n`);
|
|
147
190
|
}
|
|
148
191
|
function readOption(args, name) {
|
|
149
192
|
const prefix = `${name}=`;
|
|
@@ -176,7 +219,7 @@ function listWorkspacePackageFiles(workspaceRoot) {
|
|
|
176
219
|
withFileTypes: true
|
|
177
220
|
})){
|
|
178
221
|
if (!entry.isDirectory()) continue;
|
|
179
|
-
const packageFile =
|
|
222
|
+
const packageFile = `${directory}/${entry.name}/package.json`;
|
|
180
223
|
if (external_node_fs_default().existsSync(external_node_path_default().join(workspaceRoot, packageFile))) packageFiles.push(packageFile);
|
|
181
224
|
}
|
|
182
225
|
}
|
|
@@ -266,15 +309,36 @@ const cloudflareModernDeployCommand = 'ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=
|
|
|
266
309
|
const cloudflareModernDeploySkipBuildCommand = `${cloudflareModernDeployCommand} --skip-build`;
|
|
267
310
|
const cloudflareWranglerDeployCommand = 'wrangler deploy --config .output/wrangler.json';
|
|
268
311
|
const cloudflareWranglerDeployInvalidSkipBuildCommand = `${cloudflareWranglerDeployCommand} --skip-build`;
|
|
269
|
-
function
|
|
312
|
+
function removeStaleBackendFederationCommandSegments(command) {
|
|
313
|
+
return command.replace(/\s+&&\s+node\s+\S*scripts\/generate-node-backend-federation\.m[ct]s(?:\s+--app\s+\S+)?(?:\s+--target\s+\S+)?(?=\s+&&|$)/gu, '');
|
|
314
|
+
}
|
|
315
|
+
function updateGeneratedPackageScripts(packageJson, options = {}) {
|
|
270
316
|
const scripts = packageJson.scripts;
|
|
271
317
|
if (!scripts || 'object' != typeof scripts || Array.isArray(scripts)) return false;
|
|
272
318
|
let changed = false;
|
|
319
|
+
const apps = options.apps ?? [];
|
|
320
|
+
const app = apps.find((candidate)=>`${candidate.directory}/package.json` === options.relativePackageFile);
|
|
321
|
+
const expectedScripts = 'package.json' === options.relativePackageFile ? (0, workspace_script_plan_cjs_namespaceObject.createWorkspaceRootPackageScripts)(apps.filter((candidate)=>'shell' !== candidate.kind)) : app ? (0, workspace_script_plan_cjs_namespaceObject.createWorkspaceAppPackageScripts)(app) : void 0;
|
|
322
|
+
if (expectedScripts) {
|
|
323
|
+
for (const [name, value] of Object.entries(expectedScripts))if (scripts[name] !== value) {
|
|
324
|
+
scripts[name] = value;
|
|
325
|
+
changed = true;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
const build = scripts.build;
|
|
329
|
+
if ('string' == typeof build) {
|
|
330
|
+
const nextBuild = removeStaleBackendFederationCommandSegments(build);
|
|
331
|
+
if (nextBuild !== build) {
|
|
332
|
+
scripts.build = nextBuild;
|
|
333
|
+
changed = true;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
273
336
|
const cloudflareBuild = scripts['cloudflare:build'];
|
|
274
337
|
if ('string' == typeof cloudflareBuild) {
|
|
275
|
-
let nextCloudflareBuild = cloudflareBuild;
|
|
338
|
+
let nextCloudflareBuild = removeStaleBackendFederationCommandSegments(cloudflareBuild);
|
|
276
339
|
if (nextCloudflareBuild.includes(cloudflareModernDeployCommand) && !nextCloudflareBuild.includes(cloudflareModernDeploySkipBuildCommand)) nextCloudflareBuild = nextCloudflareBuild.replace(cloudflareModernDeployCommand, cloudflareModernDeploySkipBuildCommand);
|
|
277
340
|
nextCloudflareBuild = nextCloudflareBuild.replace(/ && node \S*scripts\/generate-public-surface-assets\.m[ct]s --app [^&]+ --target dist(?= && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build)/u, '');
|
|
341
|
+
nextCloudflareBuild = nextCloudflareBuild.replace(/ && node \S*scripts\/verify-cloudflare-output\.m[ct]s(?: --app [^&]+)?/u, '');
|
|
278
342
|
if (nextCloudflareBuild !== cloudflareBuild) {
|
|
279
343
|
scripts['cloudflare:build'] = nextCloudflareBuild;
|
|
280
344
|
changed = true;
|
|
@@ -288,9 +352,18 @@ function updateGeneratedPackageScripts(packageJson) {
|
|
|
288
352
|
return changed;
|
|
289
353
|
}
|
|
290
354
|
function normalizeStrictEffectApiMetadata(value) {
|
|
291
|
-
const api = value.api;
|
|
292
|
-
if (!api || 'object' != typeof api || Array.isArray(api)) return false;
|
|
293
355
|
let changed = false;
|
|
356
|
+
const backendFederation = value.backendFederation;
|
|
357
|
+
if (backendFederation && 'object' == typeof backendFederation && !Array.isArray(backendFederation) && Object.hasOwn(backendFederation, 'entry')) {
|
|
358
|
+
delete backendFederation.entry;
|
|
359
|
+
changed = true;
|
|
360
|
+
}
|
|
361
|
+
const api = value.api;
|
|
362
|
+
if (!api || 'object' != typeof api || Array.isArray(api)) return changed;
|
|
363
|
+
if (void 0 !== api.backendFederation) {
|
|
364
|
+
delete api.backendFederation;
|
|
365
|
+
changed = true;
|
|
366
|
+
}
|
|
294
367
|
const oldEffect = api.effect;
|
|
295
368
|
if (oldEffect && 'object' == typeof oldEffect && !Array.isArray(oldEffect)) {
|
|
296
369
|
if (void 0 === api.stem && 'string' == typeof oldEffect.stem) {
|
|
@@ -352,6 +425,38 @@ function normalizeStrictEffectApiMetadata(value) {
|
|
|
352
425
|
}
|
|
353
426
|
return changed;
|
|
354
427
|
}
|
|
428
|
+
function removeGeneratedFileIfExists(io, relativePath) {
|
|
429
|
+
return io.remove(external_node_path_default().join(io.workspaceRoot, relativePath));
|
|
430
|
+
}
|
|
431
|
+
function removeStaleBackendFederationArtifacts(io, config) {
|
|
432
|
+
let changed = false;
|
|
433
|
+
for (const relativePath of [
|
|
434
|
+
"scripts/generate-node-backend-federation.mts",
|
|
435
|
+
"scripts/proof-node-backend-federation.mts",
|
|
436
|
+
"scripts/verify-cloudflare-output.mts"
|
|
437
|
+
])changed = removeGeneratedFileIfExists(io, relativePath) || changed;
|
|
438
|
+
for (const app of (0, external_config_cjs_namespaceObject.workspaceAppsFromToolingConfig)(config))changed = removeGeneratedFileIfExists(io, external_node_path_default().join(app.directory, 'api/backend-federation.ts')) || changed;
|
|
439
|
+
return changed;
|
|
440
|
+
}
|
|
441
|
+
function updateGeneratedZeropsArtifacts(io, config) {
|
|
442
|
+
const apps = (0, external_config_cjs_namespaceObject.workspaceAppsFromToolingConfig)(config);
|
|
443
|
+
let changed = writeTextIfChanged(io, external_node_path_default().join(io.workspaceRoot, 'zerops.yaml'), `${(0, zerops_cjs_namespaceObject.createZeropsYaml)(config.workspace.packageScope, apps)}\n`);
|
|
444
|
+
changed = writeTextIfChanged(io, external_node_path_default().join(io.workspaceRoot, "scripts/materialize-zerops-runtime.mjs"), (0, workspace_scripts_cjs_namespaceObject.createZeropsRuntimeMaterializationScript)()) || changed;
|
|
445
|
+
return changed;
|
|
446
|
+
}
|
|
447
|
+
function updateGeneratedBuildIdentityModules(io, config) {
|
|
448
|
+
let changed = false;
|
|
449
|
+
for (const app of (0, external_config_cjs_namespaceObject.workspaceAppsFromToolingConfig)(config)){
|
|
450
|
+
changed = writeTextIfChanged(io, external_node_path_default().join(io.workspaceRoot, app.directory, 'src/ultramodern-build.ts'), (0, module_federation_cjs_namespaceObject.createUltramodernBuildReexportModule)()) || changed;
|
|
451
|
+
changed = writeTextIfChanged(io, external_node_path_default().join(io.workspaceRoot, app.directory, 'shared/ultramodern-build.ts'), (0, module_federation_cjs_namespaceObject.createUltramodernBuildModule)(config.workspace.packageScope, app)) || changed;
|
|
452
|
+
}
|
|
453
|
+
return changed;
|
|
454
|
+
}
|
|
455
|
+
function updateGeneratedBackendFederationContractFiles(io, config) {
|
|
456
|
+
let changed = false;
|
|
457
|
+
for (const app of (0, external_config_cjs_namespaceObject.workspaceAppsFromToolingConfig)(config))if (app.api) changed = writeTextIfChanged(io, external_node_path_default().join(io.workspaceRoot, app.directory, 'api/backend-federation.ts'), (0, backend_federation_cjs_namespaceObject.createBackendFederationContractFile)(app)) || changed;
|
|
458
|
+
return changed;
|
|
459
|
+
}
|
|
355
460
|
function replaceYamlLine(source, pattern, replacement) {
|
|
356
461
|
const updated = source.replace(pattern, replacement);
|
|
357
462
|
return {
|
|
@@ -384,22 +489,35 @@ function ensureYamlListItem(source, key, item) {
|
|
|
384
489
|
changed: true
|
|
385
490
|
};
|
|
386
491
|
}
|
|
387
|
-
function
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
const currentEntry = source.match(currentEntryPattern);
|
|
393
|
-
if (currentEntry) {
|
|
394
|
-
if (currentEntry[0] === entryLine) return {
|
|
395
|
-
source,
|
|
396
|
-
changed: false
|
|
397
|
-
};
|
|
398
|
-
return {
|
|
399
|
-
source: source.replace(currentEntryPattern, entryLine),
|
|
400
|
-
changed: true
|
|
401
|
-
};
|
|
492
|
+
function yamlEntryPattern(entryKey, scalar = false) {
|
|
493
|
+
const bareKey = entryKey.replace(/^['"]|['"]$/gu, '');
|
|
494
|
+
if (scalar) {
|
|
495
|
+
const esc = bareKey.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
496
|
+
return new RegExp(`^ {2}(?:'${esc}'|"${esc}"|${esc}): .+$`, 'gmu');
|
|
402
497
|
}
|
|
498
|
+
const packageName = bareKey.includes('@') ? bareKey.slice(0, bareKey.lastIndexOf('@')) : bareKey;
|
|
499
|
+
const esc = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
500
|
+
return new RegExp(`^ {2}(?:'${esc}@[^']+'|"${esc}@[^"]+"|${esc}@[^:'"\\s]+): .+$`, 'gmu');
|
|
501
|
+
}
|
|
502
|
+
function upsertYamlEntry(source, key, entryLine, pattern) {
|
|
503
|
+
const linePattern = new RegExp(pattern.source, 'u');
|
|
504
|
+
const lines = source.split('\n');
|
|
505
|
+
let seen = false;
|
|
506
|
+
let changed = false;
|
|
507
|
+
const out = [];
|
|
508
|
+
for (const line of lines)if (linePattern.test(line)) {
|
|
509
|
+
if (seen) {
|
|
510
|
+
changed = true;
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
seen = true;
|
|
514
|
+
if (line !== entryLine) changed = true;
|
|
515
|
+
out.push(entryLine);
|
|
516
|
+
} else out.push(line);
|
|
517
|
+
if (seen) return {
|
|
518
|
+
source: out.join('\n'),
|
|
519
|
+
changed
|
|
520
|
+
};
|
|
403
521
|
const headerPattern = new RegExp(`^${key}:\\n(?:(?: .+\\n)*)`, 'mu');
|
|
404
522
|
const header = source.match(headerPattern);
|
|
405
523
|
if (header) {
|
|
@@ -417,62 +535,43 @@ function ensureYamlMapEntry(source, key, entryKey, value) {
|
|
|
417
535
|
changed: true
|
|
418
536
|
};
|
|
419
537
|
}
|
|
538
|
+
function ensureYamlMapEntry(source, key, entryKey, value) {
|
|
539
|
+
return upsertYamlEntry(source, key, ` '${entryKey}': ${value}`, yamlEntryPattern(entryKey));
|
|
540
|
+
}
|
|
420
541
|
function ensureYamlScalarMapEntry(source, key, entryKey, value) {
|
|
421
|
-
|
|
422
|
-
const escapedEntryKey = entryKey.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
423
|
-
const currentEntryPattern = new RegExp(`^ {2}${escapedEntryKey}: .+$`, 'mu');
|
|
424
|
-
const currentEntry = source.match(currentEntryPattern);
|
|
425
|
-
if (currentEntry) {
|
|
426
|
-
if (currentEntry[0] === entryLine) return {
|
|
427
|
-
source,
|
|
428
|
-
changed: false
|
|
429
|
-
};
|
|
430
|
-
return {
|
|
431
|
-
source: source.replace(currentEntryPattern, entryLine),
|
|
432
|
-
changed: true
|
|
433
|
-
};
|
|
434
|
-
}
|
|
435
|
-
const headerPattern = new RegExp(`^${key}:\\n(?:(?: .+\\n)*)`, 'mu');
|
|
436
|
-
const header = source.match(headerPattern);
|
|
437
|
-
if (header) return {
|
|
438
|
-
source: source.replace(headerPattern, `${header[0]}${entryLine}\n`),
|
|
439
|
-
changed: true
|
|
440
|
-
};
|
|
441
|
-
return {
|
|
442
|
-
source: `${source.trimEnd()}\n${key}:\n${entryLine}\n`,
|
|
443
|
-
changed: true
|
|
444
|
-
};
|
|
542
|
+
return upsertYamlEntry(source, key, ` ${entryKey}: ${value}`, yamlEntryPattern(entryKey, true));
|
|
445
543
|
}
|
|
446
544
|
function removeYamlMapEntry(source, entryKey) {
|
|
447
|
-
const
|
|
448
|
-
const
|
|
449
|
-
|
|
450
|
-
|
|
545
|
+
const linePattern = new RegExp(yamlEntryPattern(entryKey).source, 'u');
|
|
546
|
+
const lines = source.split('\n');
|
|
547
|
+
let changed = false;
|
|
548
|
+
const out = [];
|
|
549
|
+
for (const line of lines){
|
|
550
|
+
if (linePattern.test(line)) {
|
|
551
|
+
changed = true;
|
|
552
|
+
continue;
|
|
553
|
+
}
|
|
554
|
+
out.push(line);
|
|
555
|
+
}
|
|
556
|
+
return changed ? {
|
|
557
|
+
source: out.join('\n'),
|
|
558
|
+
changed
|
|
559
|
+
} : {
|
|
451
560
|
source,
|
|
452
|
-
changed
|
|
453
|
-
};
|
|
454
|
-
return {
|
|
455
|
-
source: source.replace(currentEntryPattern, ''),
|
|
456
|
-
changed: true
|
|
561
|
+
changed
|
|
457
562
|
};
|
|
458
563
|
}
|
|
459
|
-
function ensureGeneratedPatchFile(
|
|
460
|
-
const targetPath = external_node_path_default().join(workspaceRoot, relativePatchPath);
|
|
564
|
+
function ensureGeneratedPatchFile(io, relativePatchPath, sourcePatchPath) {
|
|
565
|
+
const targetPath = external_node_path_default().join(io.workspaceRoot, relativePatchPath);
|
|
461
566
|
const patch = external_node_fs_default().readFileSync(sourcePatchPath, 'utf-8');
|
|
462
|
-
|
|
463
|
-
external_node_fs_default().mkdirSync(external_node_path_default().dirname(targetPath), {
|
|
464
|
-
recursive: true
|
|
465
|
-
});
|
|
466
|
-
external_node_fs_default().writeFileSync(targetPath, patch, 'utf-8');
|
|
467
|
-
return true;
|
|
567
|
+
return io.write(targetPath, patch);
|
|
468
568
|
}
|
|
469
|
-
function removeGeneratedPatchFileIfUnchanged(
|
|
470
|
-
const targetPath = external_node_path_default().join(workspaceRoot, relativePatchPath);
|
|
569
|
+
function removeGeneratedPatchFileIfUnchanged(io, relativePatchPath, sourcePatchPath) {
|
|
570
|
+
const targetPath = external_node_path_default().join(io.workspaceRoot, relativePatchPath);
|
|
471
571
|
if (!external_node_fs_default().existsSync(targetPath)) return false;
|
|
472
572
|
const patch = external_node_fs_default().readFileSync(sourcePatchPath, 'utf-8');
|
|
473
573
|
if (external_node_fs_default().readFileSync(targetPath, 'utf-8') !== patch) return false;
|
|
474
|
-
|
|
475
|
-
return true;
|
|
574
|
+
return io.remove(targetPath);
|
|
476
575
|
}
|
|
477
576
|
function workspaceUsesDependency(workspaceRoot, packageName) {
|
|
478
577
|
const packageJsonPaths = [
|
|
@@ -509,20 +608,20 @@ function workspaceUsesDependency(workspaceRoot, packageName) {
|
|
|
509
608
|
}
|
|
510
609
|
return false;
|
|
511
610
|
}
|
|
512
|
-
function ensureGeneratedDeclarationPatches(
|
|
611
|
+
function ensureGeneratedDeclarationPatches(io, options) {
|
|
513
612
|
let changed = false;
|
|
514
|
-
changed = ensureGeneratedPatchFile(
|
|
515
|
-
changed = ensureGeneratedPatchFile(
|
|
516
|
-
changed = ensureGeneratedPatchFile(
|
|
517
|
-
changed = options.includeDrizzleOrmPatch ? ensureGeneratedPatchFile(
|
|
613
|
+
changed = ensureGeneratedPatchFile(io, moduleFederationModernJsPatchPath, moduleFederationModernJsPatchSourcePath) || changed;
|
|
614
|
+
changed = ensureGeneratedPatchFile(io, moduleFederationBridgeReactPatchPath, moduleFederationBridgeReactPatchSourcePath) || changed;
|
|
615
|
+
changed = ensureGeneratedPatchFile(io, effectDeclarationPatchPath, effectDeclarationPatchSourcePath) || changed;
|
|
616
|
+
changed = options.includeDrizzleOrmPatch ? ensureGeneratedPatchFile(io, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed : removeGeneratedPatchFileIfUnchanged(io, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed;
|
|
518
617
|
return changed;
|
|
519
618
|
}
|
|
520
|
-
function updateGeneratedPnpmWorkspacePolicy(
|
|
521
|
-
const workspaceFile = external_node_path_default().join(workspaceRoot, 'pnpm-workspace.yaml');
|
|
619
|
+
function updateGeneratedPnpmWorkspacePolicy(io) {
|
|
620
|
+
const workspaceFile = external_node_path_default().join(io.workspaceRoot, 'pnpm-workspace.yaml');
|
|
522
621
|
if (!external_node_fs_default().existsSync(workspaceFile)) return false;
|
|
523
622
|
let source = external_node_fs_default().readFileSync(workspaceFile, 'utf-8');
|
|
524
623
|
let changed = false;
|
|
525
|
-
const usesDrizzleOrm = workspaceUsesDependency(workspaceRoot, 'drizzle-orm');
|
|
624
|
+
const usesDrizzleOrm = workspaceUsesDependency(io.workspaceRoot, 'drizzle-orm');
|
|
526
625
|
const replacements = [
|
|
527
626
|
[
|
|
528
627
|
/^ {4}'@effect\/vitest>effect': .+$/mu,
|
|
@@ -582,12 +681,11 @@ function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
|
|
|
582
681
|
const drizzleOrmPatch = usesDrizzleOrm ? ensureYamlMapEntry(source, 'patchedDependencies', `drizzle-orm@${versions_cjs_namespaceObject.DRIZZLE_ORM_VERSION}`, drizzleOrmDeclarationPatchPath) : removeYamlMapEntry(source, `drizzle-orm@${versions_cjs_namespaceObject.DRIZZLE_ORM_VERSION}`);
|
|
583
682
|
source = drizzleOrmPatch.source;
|
|
584
683
|
changed = drizzleOrmPatch.changed || changed;
|
|
585
|
-
if (changed)
|
|
684
|
+
if (changed) io.write(workspaceFile, source);
|
|
586
685
|
return changed;
|
|
587
686
|
}
|
|
588
|
-
function updateUltramodernConfig(
|
|
589
|
-
const configPath = external_node_path_default().join(workspaceRoot, '.modernjs/ultramodern.json');
|
|
590
|
-
const config = readJsonFile(configPath);
|
|
687
|
+
function updateUltramodernConfig(io, config, packageSource) {
|
|
688
|
+
const configPath = external_node_path_default().join(io.workspaceRoot, '.modernjs/ultramodern.json');
|
|
591
689
|
config.packageSource = {
|
|
592
690
|
strategy: packageSource.strategy,
|
|
593
691
|
modernPackageVersion: packageSource.modernPackageVersion,
|
|
@@ -602,73 +700,145 @@ function updateUltramodernConfig(workspaceRoot, packageSource) {
|
|
|
602
700
|
} : {}
|
|
603
701
|
};
|
|
604
702
|
for (const app of config.topology?.apps ?? [])if (app && 'object' == typeof app && !Array.isArray(app)) normalizeStrictEffectApiMetadata(app);
|
|
605
|
-
writeJsonFile(configPath, config);
|
|
703
|
+
writeJsonFile(io, configPath, config);
|
|
606
704
|
}
|
|
607
|
-
function writeJsonIfChanged(filePath, value) {
|
|
608
|
-
|
|
609
|
-
if (external_node_fs_default().existsSync(filePath) && external_node_fs_default().readFileSync(filePath, 'utf-8') === next) return false;
|
|
610
|
-
external_node_fs_default().mkdirSync(external_node_path_default().dirname(filePath), {
|
|
611
|
-
recursive: true
|
|
612
|
-
});
|
|
613
|
-
external_node_fs_default().writeFileSync(filePath, next, 'utf-8');
|
|
614
|
-
return true;
|
|
705
|
+
function writeJsonIfChanged(io, filePath, value) {
|
|
706
|
+
return io.write(filePath, `${JSON.stringify(value, null, 2)}\n`);
|
|
615
707
|
}
|
|
616
|
-
function writeTextIfChanged(filePath, value) {
|
|
617
|
-
|
|
618
|
-
external_node_fs_default().mkdirSync(external_node_path_default().dirname(filePath), {
|
|
619
|
-
recursive: true
|
|
620
|
-
});
|
|
621
|
-
external_node_fs_default().writeFileSync(filePath, value, 'utf-8');
|
|
622
|
-
return true;
|
|
708
|
+
function writeTextIfChanged(io, filePath, value) {
|
|
709
|
+
return io.write(filePath, value);
|
|
623
710
|
}
|
|
624
|
-
function ensureGeneratedIgnoreRules(
|
|
625
|
-
const gitignorePath = external_node_path_default().join(workspaceRoot, '.gitignore');
|
|
711
|
+
function ensureGeneratedIgnoreRules(io) {
|
|
712
|
+
const gitignorePath = external_node_path_default().join(io.workspaceRoot, '.gitignore');
|
|
626
713
|
const existing = external_node_fs_default().existsSync(gitignorePath) ? external_node_fs_default().readFileSync(gitignorePath, 'utf-8') : '';
|
|
627
714
|
const lines = 0 === existing.trimEnd().length ? [] : existing.trimEnd().split(/\r?\n/u);
|
|
628
715
|
let changed = false;
|
|
629
716
|
for (const rule of [
|
|
630
717
|
'.mf/',
|
|
631
718
|
'**/.mf/',
|
|
632
|
-
'dist-cloudflare/'
|
|
719
|
+
'dist-cloudflare/',
|
|
720
|
+
'.output/',
|
|
721
|
+
'**/.output/',
|
|
722
|
+
'.modern-js/',
|
|
723
|
+
'**/.modern-js/'
|
|
633
724
|
])if (!lines.includes(rule)) {
|
|
634
725
|
lines.push(rule);
|
|
635
726
|
changed = true;
|
|
636
727
|
}
|
|
637
728
|
if (!changed) return false;
|
|
638
|
-
|
|
639
|
-
external_node_fs_default().writeFileSync(gitignorePath, next, 'utf-8');
|
|
640
|
-
return true;
|
|
729
|
+
return io.write(gitignorePath, `${lines.join('\n')}\n`);
|
|
641
730
|
}
|
|
642
|
-
function updateGeneratedTypeScriptSurfaces(
|
|
731
|
+
function updateGeneratedTypeScriptSurfaces(io, config) {
|
|
643
732
|
let changed = false;
|
|
644
733
|
const apps = (0, external_config_cjs_namespaceObject.workspaceAppsFromToolingConfig)(config);
|
|
645
734
|
const remotes = apps.filter((app)=>'shell' !== app.kind);
|
|
646
|
-
changed = writeJsonIfChanged(external_node_path_default().join(workspaceRoot, 'tsconfig.base.json'), (0, package_json_cjs_namespaceObject.createTsConfigBase)()) || changed;
|
|
647
|
-
changed = ensureGeneratedIgnoreRules(
|
|
735
|
+
changed = writeJsonIfChanged(io, external_node_path_default().join(io.workspaceRoot, 'tsconfig.base.json'), (0, package_json_cjs_namespaceObject.createTsConfigBase)()) || changed;
|
|
736
|
+
changed = ensureGeneratedIgnoreRules(io) || changed;
|
|
648
737
|
for (const sharedPackage of [
|
|
649
738
|
'packages/shared-contracts',
|
|
650
739
|
'packages/shared-design-tokens'
|
|
651
|
-
])changed = writeJsonIfChanged(external_node_path_default().join(workspaceRoot, sharedPackage, 'tsconfig.json'), (0, package_json_cjs_namespaceObject.createSharedPackageTsConfig)(sharedPackage)) || changed;
|
|
740
|
+
])changed = writeJsonIfChanged(io, external_node_path_default().join(io.workspaceRoot, sharedPackage, 'tsconfig.json'), (0, package_json_cjs_namespaceObject.createSharedPackageTsConfig)(sharedPackage)) || changed;
|
|
652
741
|
for (const app of apps){
|
|
653
|
-
changed = writeJsonIfChanged(external_node_path_default().join(workspaceRoot, app.directory, 'tsconfig.json'), (0, package_json_cjs_namespaceObject.createAppTsConfig)(app, remotes)) || changed;
|
|
654
|
-
changed = writeJsonIfChanged(external_node_path_default().join(workspaceRoot, app.directory, 'tsconfig.mf-types.json'), (0, package_json_cjs_namespaceObject.createAppMfTypesTsConfig)(app)) || changed;
|
|
655
|
-
changed = writeTextIfChanged(external_node_path_default().join(workspaceRoot, app.directory, 'src/modern-app-env.d.ts'), (0, app_files_cjs_namespaceObject.createAppEnvDts)(app, remotes)) || changed;
|
|
742
|
+
changed = writeJsonIfChanged(io, external_node_path_default().join(io.workspaceRoot, app.directory, 'tsconfig.json'), (0, package_json_cjs_namespaceObject.createAppTsConfig)(app, remotes)) || changed;
|
|
743
|
+
changed = writeJsonIfChanged(io, external_node_path_default().join(io.workspaceRoot, app.directory, 'tsconfig.mf-types.json'), (0, package_json_cjs_namespaceObject.createAppMfTypesTsConfig)(app)) || changed;
|
|
744
|
+
changed = writeTextIfChanged(io, external_node_path_default().join(io.workspaceRoot, app.directory, 'src/modern-app-env.d.ts'), (0, app_files_cjs_namespaceObject.createAppEnvDts)(app, remotes)) || changed;
|
|
656
745
|
}
|
|
657
746
|
return changed;
|
|
658
747
|
}
|
|
659
|
-
function updateGeneratedModernConfigs(
|
|
748
|
+
function updateGeneratedModernConfigs(io, config) {
|
|
660
749
|
let changed = false;
|
|
661
750
|
const apps = (0, external_config_cjs_namespaceObject.workspaceAppsFromToolingConfig)(config);
|
|
662
|
-
|
|
751
|
+
const remotes = apps.filter((app)=>'shell' !== app.kind);
|
|
752
|
+
for (const app of apps)changed = writeTextIfChanged(io, external_node_path_default().join(io.workspaceRoot, app.directory, 'modern.config.ts'), (0, module_federation_cjs_namespaceObject.createAppModernConfig)(config.workspace.packageScope, app, remotes)) || changed;
|
|
663
753
|
return changed;
|
|
664
754
|
}
|
|
665
|
-
function
|
|
666
|
-
const
|
|
755
|
+
function ensureGeneratedOxfmtIgnorePatterns(io) {
|
|
756
|
+
const configPath = external_node_path_default().join(io.workspaceRoot, 'oxfmt.config.ts');
|
|
757
|
+
if (!external_node_fs_default().existsSync(configPath)) return false;
|
|
758
|
+
const source = external_node_fs_default().readFileSync(configPath, 'utf-8');
|
|
759
|
+
const requiredPatterns = [
|
|
760
|
+
'.modernjs',
|
|
761
|
+
'.output',
|
|
762
|
+
'**/modern-tanstack/**',
|
|
763
|
+
'**/routeTree.gen.*'
|
|
764
|
+
];
|
|
765
|
+
const warnUnparseable = ()=>{
|
|
766
|
+
const message = `Could not update oxfmt.config.ts ignorePatterns automatically; add these entries manually: ${requiredPatterns.join(', ')}.`;
|
|
767
|
+
if (io.dryRun) io.log(message);
|
|
768
|
+
else process.stderr.write(`[ultramodern] ${message}\n`);
|
|
769
|
+
};
|
|
770
|
+
const anchor = source.indexOf('ignorePatterns:');
|
|
771
|
+
if (-1 === anchor) {
|
|
772
|
+
warnUnparseable();
|
|
773
|
+
return false;
|
|
774
|
+
}
|
|
775
|
+
const openBracket = source.indexOf('[', anchor);
|
|
776
|
+
if (-1 === openBracket) {
|
|
777
|
+
warnUnparseable();
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
let depth = 0;
|
|
781
|
+
let closeBracket = -1;
|
|
782
|
+
let stringQuote;
|
|
783
|
+
for(let index = openBracket; index < source.length; index += 1){
|
|
784
|
+
const char = source[index];
|
|
785
|
+
if (stringQuote) {
|
|
786
|
+
if ('\\' === char) index += 1;
|
|
787
|
+
else if (char === stringQuote) stringQuote = void 0;
|
|
788
|
+
continue;
|
|
789
|
+
}
|
|
790
|
+
if ("'" === char || '"' === char || '`' === char) stringQuote = char;
|
|
791
|
+
else if ('[' === char) depth += 1;
|
|
792
|
+
else if (']' === char) {
|
|
793
|
+
depth -= 1;
|
|
794
|
+
if (0 === depth) {
|
|
795
|
+
closeBracket = index;
|
|
796
|
+
break;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
if (-1 === closeBracket) {
|
|
801
|
+
warnUnparseable();
|
|
802
|
+
return false;
|
|
803
|
+
}
|
|
804
|
+
const body = source.slice(openBracket + 1, closeBracket);
|
|
805
|
+
if (body.includes('...')) {
|
|
806
|
+
warnUnparseable();
|
|
807
|
+
return false;
|
|
808
|
+
}
|
|
809
|
+
const literalPattern = /(['"`])((?:\\.|(?!\1).)*)\1/g;
|
|
810
|
+
const existing = new Set();
|
|
811
|
+
for (const match of body.matchAll(literalPattern))existing.add(match[2]);
|
|
812
|
+
const missing = requiredPatterns.filter((pattern)=>!existing.has(pattern));
|
|
813
|
+
if (0 === missing.length) return false;
|
|
814
|
+
const bodyLines = body.split('\n');
|
|
815
|
+
let indent = ' ';
|
|
816
|
+
let quote = "'";
|
|
817
|
+
for(let index = bodyLines.length - 1; index >= 0; index -= 1){
|
|
818
|
+
const literal = bodyLines[index].match(/^(\s*)(['"`])/u);
|
|
819
|
+
if (literal) {
|
|
820
|
+
indent = literal[1];
|
|
821
|
+
quote = literal[2];
|
|
822
|
+
break;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
const head = source.slice(0, closeBracket);
|
|
826
|
+
const rest = source.slice(closeBracket);
|
|
827
|
+
const tailMatch = head.match(/(\r?\n[ \t]*)$/u);
|
|
828
|
+
const tail = tailMatch ? tailMatch[1] : '\n';
|
|
829
|
+
let bodyContent = tailMatch ? head.slice(0, head.length - tail.length) : head;
|
|
830
|
+
if (!/[[,]\s*$/u.test(bodyContent)) bodyContent = `${bodyContent},`;
|
|
831
|
+
const insertionLines = missing.map((pattern)=>`${indent}${quote}${pattern}${quote},`).join('\n');
|
|
832
|
+
const nextSource = `${bodyContent}\n${insertionLines}${tail}${rest}`;
|
|
833
|
+
return io.write(configPath, nextSource);
|
|
834
|
+
}
|
|
835
|
+
function updateReferenceTopology(io) {
|
|
836
|
+
const topologyPath = external_node_path_default().join(io.workspaceRoot, 'topology/reference-topology.json');
|
|
667
837
|
if (!external_node_fs_default().existsSync(topologyPath)) return false;
|
|
668
838
|
const topology = readJsonFile(topologyPath);
|
|
669
839
|
let changed = false;
|
|
670
840
|
for (const vertical of topology.verticals ?? [])if (vertical && 'object' == typeof vertical && !Array.isArray(vertical)) changed = normalizeStrictEffectApiMetadata(vertical) || changed;
|
|
671
|
-
if (changed) writeJsonFile(topologyPath, topology);
|
|
841
|
+
if (changed) writeJsonFile(io, topologyPath, topology);
|
|
672
842
|
return changed;
|
|
673
843
|
}
|
|
674
844
|
function createMigrationPackageSource(args, current) {
|
|
@@ -721,25 +891,56 @@ function runPnpmLockfileRefresh(context) {
|
|
|
721
891
|
function runMigrateStrictEffect(args, context) {
|
|
722
892
|
if (args.includes('--help') || args.includes('-h')) {
|
|
723
893
|
process.stdout.write(`Usage:
|
|
724
|
-
modern-js-create ultramodern migrate-strict-effect --version <version> [--skip-install]
|
|
894
|
+
modern-js-create ultramodern migrate-strict-effect --version <version> [--dry-run] [--skip-install]
|
|
725
895
|
|
|
726
896
|
Updates generated UltraModern package-source metadata, Modern package aliases,
|
|
727
897
|
framework-owned toolchain pins, direct Effect API topology metadata, strict
|
|
728
898
|
Effect pnpm overrides/trust policy, framework-owned TypeScript config
|
|
729
899
|
surfaces, and the pnpm lockfile. Source code still has to pass pnpm api:check
|
|
730
900
|
and pnpm contract:check.
|
|
901
|
+
|
|
902
|
+
When the compact config is absent but legacy UltraModern 3.2 metadata is
|
|
903
|
+
present, the compact config is synthesized from it first. Shell-only
|
|
904
|
+
workspaces skip the backend-federation and Zerops runtime stages. Pass
|
|
905
|
+
--dry-run to print the planned filesystem changes without writing anything
|
|
906
|
+
(implies --skip-install).
|
|
731
907
|
`);
|
|
732
908
|
return 0;
|
|
733
909
|
}
|
|
734
|
-
const
|
|
910
|
+
const dryRun = hasFlag(args, '--dry-run');
|
|
911
|
+
const skipInstall = dryRun || hasFlag(args, '--skip-install');
|
|
912
|
+
const io = createMigrationIo(context.workspaceRoot, dryRun);
|
|
913
|
+
const compactPath = external_node_path_default().join(io.workspaceRoot, '.modernjs/ultramodern.json');
|
|
914
|
+
let raw;
|
|
915
|
+
if (external_node_fs_default().existsSync(compactPath)) raw = readJsonFile(compactPath);
|
|
916
|
+
else {
|
|
917
|
+
const synthesized = (0, external_config_cjs_namespaceObject.synthesizeCompactUltramodernConfig)(io.workspaceRoot);
|
|
918
|
+
if (!synthesized) throw new Error("Missing .modernjs/ultramodern.json and no legacy UltraModern metadata (.modernjs/ultramodern-generated-contract.json) was found to synthesize it from.");
|
|
919
|
+
raw = synthesized.compact;
|
|
920
|
+
io.write(compactPath, `${JSON.stringify(raw, null, 2)}\n`);
|
|
921
|
+
io.log(`Synthesized .modernjs/ultramodern.json from legacy metadata: ${synthesized.sources.join(', ')}.`);
|
|
922
|
+
if (synthesized.missing.length > 0) io.log(`Legacy metadata not found (using defaults): ${synthesized.missing.join(', ')}.`);
|
|
923
|
+
}
|
|
924
|
+
const current = (0, external_config_cjs_namespaceObject.normalizeCompactUltramodernConfig)(io.workspaceRoot, raw);
|
|
735
925
|
const packageSource = createMigrationPackageSource(args, current);
|
|
736
|
-
updateUltramodernConfig(
|
|
737
|
-
updateReferenceTopology(
|
|
738
|
-
const migrated = (0, external_config_cjs_namespaceObject.
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
926
|
+
updateUltramodernConfig(io, raw, packageSource);
|
|
927
|
+
updateReferenceTopology(io);
|
|
928
|
+
const migrated = (0, external_config_cjs_namespaceObject.normalizeCompactUltramodernConfig)(io.workspaceRoot, raw);
|
|
929
|
+
const migratedApps = (0, external_config_cjs_namespaceObject.workspaceAppsFromToolingConfig)(migrated);
|
|
930
|
+
const shellOnly = !migrated.topology.apps.some((app)=>app.api);
|
|
931
|
+
if (shellOnly) io.log('Shell-only workspace: skipping backend-federation and Zerops runtime stages.');
|
|
932
|
+
else {
|
|
933
|
+
removeStaleBackendFederationArtifacts(io, migrated);
|
|
934
|
+
updateGeneratedZeropsArtifacts(io, migrated);
|
|
935
|
+
updateGeneratedBackendFederationContractFiles(io, migrated);
|
|
936
|
+
}
|
|
937
|
+
if (dryRun) io.log("would refresh generated tool wrapper scripts under scripts/");
|
|
938
|
+
else (0, workspace_scripts_cjs_namespaceObject.writeGeneratedToolWrapperScripts)(io.workspaceRoot);
|
|
939
|
+
updateGeneratedBuildIdentityModules(io, migrated);
|
|
940
|
+
updateGeneratedTypeScriptSurfaces(io, migrated);
|
|
941
|
+
updateGeneratedModernConfigs(io, migrated);
|
|
942
|
+
for (const relativePackageFile of listWorkspacePackageFiles(io.workspaceRoot)){
|
|
943
|
+
const packageFile = external_node_path_default().join(io.workspaceRoot, relativePackageFile);
|
|
743
944
|
const packageJson = readJsonFile(packageFile);
|
|
744
945
|
if ('package.json' === relativePackageFile) {
|
|
745
946
|
packageJson.modernjs ??= {};
|
|
@@ -748,21 +949,28 @@ and pnpm contract:check.
|
|
|
748
949
|
config: './.modernjs/ultramodern.json'
|
|
749
950
|
};
|
|
750
951
|
}
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
952
|
+
updateModernDependencies(packageJson, packageSource);
|
|
953
|
+
updateGeneratedToolingDependencies(packageJson);
|
|
954
|
+
updateGeneratedPackageScripts(packageJson, {
|
|
955
|
+
relativePackageFile,
|
|
956
|
+
apps: migratedApps
|
|
957
|
+
});
|
|
958
|
+
writeJsonFile(io, packageFile, packageJson);
|
|
959
|
+
}
|
|
960
|
+
updateGeneratedPnpmWorkspacePolicy(io);
|
|
961
|
+
ensureGeneratedDeclarationPatches(io, {
|
|
962
|
+
includeDrizzleOrmPatch: workspaceUsesDependency(io.workspaceRoot, 'drizzle-orm')
|
|
761
963
|
});
|
|
762
|
-
|
|
964
|
+
ensureGeneratedOxfmtIgnorePatterns(io);
|
|
965
|
+
if (!skipInstall) {
|
|
763
966
|
const status = runPnpmLockfileRefresh(context);
|
|
764
967
|
if (0 !== status) return status;
|
|
765
968
|
}
|
|
969
|
+
if (dryRun) {
|
|
970
|
+
for (const line of io.plan)process.stdout.write(`${line}\n`);
|
|
971
|
+
process.stdout.write(`[dry-run] migrate-strict-effect would migrate UltraModern strict Effect metadata to ${packageSource.modernPackageVersion}.\n`);
|
|
972
|
+
return 0;
|
|
973
|
+
}
|
|
766
974
|
process.stdout.write(`UltraModern strict Effect metadata migrated to ${packageSource.modernPackageVersion}. Run pnpm api:check && pnpm contract:check next.\n`);
|
|
767
975
|
return 0;
|
|
768
976
|
}
|
|
@@ -775,6 +983,140 @@ function runSkills(args, context) {
|
|
|
775
983
|
], context);
|
|
776
984
|
throw new Error('Usage: modern-js-create ultramodern skills <install|check>');
|
|
777
985
|
}
|
|
986
|
+
const resolveCloudflareOutputVerifyTargets = (args, context)=>{
|
|
987
|
+
const outputDirectory = readOption(args, '--output');
|
|
988
|
+
const appId = readOption(args, '--app');
|
|
989
|
+
if (outputDirectory && appId) throw new Error('Use either --app or --output, not both.');
|
|
990
|
+
const targets = outputDirectory ? [
|
|
991
|
+
{
|
|
992
|
+
label: outputDirectory,
|
|
993
|
+
outputDirectory: external_node_path_default().resolve(context.invocationCwd, outputDirectory)
|
|
994
|
+
}
|
|
995
|
+
] : (0, external_config_cjs_namespaceObject.workspaceAppsFromToolingConfig)((0, external_config_cjs_namespaceObject.readUltramodernConfig)(context.workspaceRoot)).filter((app)=>!appId || app.id === appId).map((app)=>({
|
|
996
|
+
label: app.id,
|
|
997
|
+
outputDirectory: external_node_path_default().join(context.workspaceRoot, app.directory, '.output')
|
|
998
|
+
}));
|
|
999
|
+
if (0 === targets.length) throw new Error(`No generated UltraModern app matched ${appId}.`);
|
|
1000
|
+
return targets;
|
|
1001
|
+
};
|
|
1002
|
+
const renderCloudflareOutputVerifyModule = ({ workspaceRoot, targets, scanRoots, importWorker })=>`
|
|
1003
|
+
import { createRequire } from 'node:module';
|
|
1004
|
+
import path from 'node:path';
|
|
1005
|
+
|
|
1006
|
+
const workspaceRoot = ${JSON.stringify(workspaceRoot)};
|
|
1007
|
+
const targets = ${JSON.stringify(targets, null, 2)};
|
|
1008
|
+
const scanRoots = ${JSON.stringify(scanRoots)};
|
|
1009
|
+
const verifierRequire = createRequire(path.join(workspaceRoot, 'package.json'));
|
|
1010
|
+
const {
|
|
1011
|
+
verifyCloudflareOutput,
|
|
1012
|
+
verifyCloudflareOutputMutationPolicy,
|
|
1013
|
+
} = verifierRequire('@modern-js/app-tools/cloudflare-output-verifier');
|
|
1014
|
+
|
|
1015
|
+
let failed = false;
|
|
1016
|
+
for (const target of targets) {
|
|
1017
|
+
const result = await verifyCloudflareOutput({
|
|
1018
|
+
outputDirectory: target.outputDirectory,
|
|
1019
|
+
importWorker: ${JSON.stringify(importWorker)},
|
|
1020
|
+
});
|
|
1021
|
+
if (result.ok) {
|
|
1022
|
+
console.log(\`[ultramodern] Cloudflare output verified: \${target.label}\`);
|
|
1023
|
+
} else {
|
|
1024
|
+
failed = true;
|
|
1025
|
+
console.error(\`[ultramodern] Cloudflare output failed: \${target.label}\`);
|
|
1026
|
+
for (const issue of result.issues) {
|
|
1027
|
+
console.error(\`- \${issue.code}: \${issue.message}\${issue.path ? \` (\${issue.path})\` : ''}\`);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
if (scanRoots.length > 0) {
|
|
1033
|
+
const policyResult = await verifyCloudflareOutputMutationPolicy({ scanRoots });
|
|
1034
|
+
if (!policyResult.ok) {
|
|
1035
|
+
failed = true;
|
|
1036
|
+
console.error('[ultramodern] generated-output mutation policy failed');
|
|
1037
|
+
for (const issue of policyResult.issues) {
|
|
1038
|
+
console.error(\`- \${issue.code}: \${issue.message}\${issue.path ? \` (\${issue.path})\` : ''}\`);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
process.exit(failed ? 1 : 0);
|
|
1044
|
+
`;
|
|
1045
|
+
function runCloudflareOutputVerify(args, context) {
|
|
1046
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
1047
|
+
process.stdout.write(`Usage:
|
|
1048
|
+
modern-js-create ultramodern cloudflare-output-verify [--app <id> | --output <dir>] [--no-import-worker] [--no-source-scan]
|
|
1049
|
+
|
|
1050
|
+
Verifies generated Cloudflare output against the UltraModern worker contract.
|
|
1051
|
+
Without --app or --output, every generated workspace app is verified.
|
|
1052
|
+
`);
|
|
1053
|
+
return 0;
|
|
1054
|
+
}
|
|
1055
|
+
const source = renderCloudflareOutputVerifyModule({
|
|
1056
|
+
workspaceRoot: context.workspaceRoot,
|
|
1057
|
+
targets: resolveCloudflareOutputVerifyTargets(args, context),
|
|
1058
|
+
scanRoots: hasFlag(args, '--no-source-scan') ? [] : [
|
|
1059
|
+
context.workspaceRoot
|
|
1060
|
+
],
|
|
1061
|
+
importWorker: !hasFlag(args, '--no-import-worker')
|
|
1062
|
+
});
|
|
1063
|
+
return runRenderedModule(source, context);
|
|
1064
|
+
}
|
|
1065
|
+
const resolveRoutesGenerateTargets = (args, context)=>{
|
|
1066
|
+
const appId = readOption(args, '--app');
|
|
1067
|
+
const targets = (0, external_config_cjs_namespaceObject.workspaceAppsFromToolingConfig)((0, external_config_cjs_namespaceObject.readUltramodernConfig)(context.workspaceRoot)).filter((app)=>!appId || app.id === appId).map((app)=>({
|
|
1068
|
+
label: app.id,
|
|
1069
|
+
appDirectory: external_node_path_default().join(context.workspaceRoot, app.directory)
|
|
1070
|
+
}));
|
|
1071
|
+
if (0 === targets.length) throw new Error(`No generated UltraModern app matched ${appId ?? '<any>'}.`);
|
|
1072
|
+
return targets;
|
|
1073
|
+
};
|
|
1074
|
+
const renderRoutesGenerateModule = ({ workspaceRoot, targets })=>`
|
|
1075
|
+
import { createRequire } from 'node:module';
|
|
1076
|
+
import path from 'node:path';
|
|
1077
|
+
import { pathToFileURL } from 'node:url';
|
|
1078
|
+
|
|
1079
|
+
const workspaceRoot = ${JSON.stringify(workspaceRoot)};
|
|
1080
|
+
const targets = ${JSON.stringify(targets, null, 2)};
|
|
1081
|
+
const appRequire = createRequire(path.join(workspaceRoot, 'package.json'));
|
|
1082
|
+
const pluginUrl = pathToFileURL(
|
|
1083
|
+
appRequire.resolve('@modern-js/plugin-tanstack'),
|
|
1084
|
+
).href;
|
|
1085
|
+
const { generateTanstackRouteArtifacts } = await import(pluginUrl);
|
|
1086
|
+
|
|
1087
|
+
let failed = false;
|
|
1088
|
+
// Sequential — the app-tools cli singleton is not re-entrant.
|
|
1089
|
+
for (const target of targets) {
|
|
1090
|
+
try {
|
|
1091
|
+
await generateTanstackRouteArtifacts({ appDirectory: target.appDirectory });
|
|
1092
|
+
console.log(\`[ultramodern] TanStack route artifacts generated: \${target.label}\`);
|
|
1093
|
+
} catch (error) {
|
|
1094
|
+
failed = true;
|
|
1095
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1096
|
+
console.error(\`[ultramodern] TanStack route generation failed: \${target.label}\`);
|
|
1097
|
+
console.error(\`- \${message}\`);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
process.exit(failed ? 1 : 0);
|
|
1102
|
+
`;
|
|
1103
|
+
function runRoutesGenerate(args, context) {
|
|
1104
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
1105
|
+
process.stdout.write(`Usage:
|
|
1106
|
+
modern-js-create ultramodern routes-generate [--app <id>]
|
|
1107
|
+
|
|
1108
|
+
Regenerates TanStack route artifacts (router.gen.ts, register.gen.d.ts) for
|
|
1109
|
+
generated UltraModern apps without running dev or build. Without --app, every
|
|
1110
|
+
generated workspace app is regenerated.
|
|
1111
|
+
`);
|
|
1112
|
+
return 0;
|
|
1113
|
+
}
|
|
1114
|
+
const source = renderRoutesGenerateModule({
|
|
1115
|
+
workspaceRoot: context.workspaceRoot,
|
|
1116
|
+
targets: resolveRoutesGenerateTargets(args, context)
|
|
1117
|
+
});
|
|
1118
|
+
return runRenderedModule(source, context);
|
|
1119
|
+
}
|
|
778
1120
|
async function runUltramodernToolingCli(args, workspaceRoot = process.env.ULTRAMODERN_WORKSPACE_ROOT ?? process.cwd()) {
|
|
779
1121
|
try {
|
|
780
1122
|
const [command, ...rest] = args;
|
|
@@ -788,25 +1130,25 @@ async function runUltramodernToolingCli(args, workspaceRoot = process.env.ULTRAM
|
|
|
788
1130
|
case '-h':
|
|
789
1131
|
printHelp();
|
|
790
1132
|
return 0;
|
|
791
|
-
case
|
|
1133
|
+
case tooling_command_catalog_cjs_namespaceObject.GENERATED_TOOLING_COMMANDS.validate.command:
|
|
792
1134
|
return runValidate(context);
|
|
793
|
-
case
|
|
794
|
-
return spawnNodeScript("templates/workspace-scripts/ultramodern-typecheck.mjs", rest, context, {
|
|
795
|
-
cwd: context.invocationCwd
|
|
796
|
-
});
|
|
797
|
-
case 'mf-types':
|
|
1135
|
+
case tooling_command_catalog_cjs_namespaceObject.GENERATED_TOOLING_COMMANDS.mfTypes.command:
|
|
798
1136
|
return runMfTypes(rest, context);
|
|
799
|
-
case
|
|
1137
|
+
case tooling_command_catalog_cjs_namespaceObject.GENERATED_TOOLING_COMMANDS.migrateStrictEffect.command:
|
|
800
1138
|
return runMigrateStrictEffect(rest, context);
|
|
801
|
-
case
|
|
802
|
-
return
|
|
803
|
-
case
|
|
804
|
-
return
|
|
805
|
-
case '
|
|
806
|
-
return
|
|
1139
|
+
case tooling_command_catalog_cjs_namespaceObject.GENERATED_TOOLING_COMMANDS.cloudflareOutputVerify.command:
|
|
1140
|
+
return runCloudflareOutputVerify(rest, context);
|
|
1141
|
+
case tooling_command_catalog_cjs_namespaceObject.GENERATED_TOOLING_COMMANDS.routesGenerate.command:
|
|
1142
|
+
return runRoutesGenerate(rest, context);
|
|
1143
|
+
case 'sync-delivery-unit':
|
|
1144
|
+
return (0, delivery_unit_sync_cjs_namespaceObject.runSyncDeliveryUnit)(rest, context);
|
|
807
1145
|
case 'skills':
|
|
808
1146
|
return runSkills(rest, context);
|
|
809
1147
|
default:
|
|
1148
|
+
{
|
|
1149
|
+
const templateBackedStatus = runTemplateBackedToolingCommand(command ?? '', rest, context);
|
|
1150
|
+
if (void 0 !== templateBackedStatus) return templateBackedStatus;
|
|
1151
|
+
}
|
|
810
1152
|
throw new Error(`Unknown UltraModern command: ${command}`);
|
|
811
1153
|
}
|
|
812
1154
|
} catch (error) {
|