@bleedingdev/modern-js-create 3.4.0-ultramodern.12 → 3.4.0-ultramodern.14
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 +13 -11
- package/dist/cjs/index.cjs +36 -3
- package/dist/cjs/locale/en.cjs +10 -0
- package/dist/cjs/locale/zh.cjs +10 -0
- package/dist/cjs/ultramodern-tooling/commands.cjs +185 -0
- package/dist/cjs/ultramodern-tooling/config.cjs +248 -0
- package/dist/cjs/ultramodern-workspace/add-vertical.cjs +64 -25
- package/dist/cjs/ultramodern-workspace/bridge-config.cjs +327 -0
- package/dist/cjs/ultramodern-workspace/codesmith.cjs +1 -0
- package/dist/cjs/ultramodern-workspace/contracts.cjs +119 -653
- package/dist/cjs/ultramodern-workspace/descriptors.cjs +4 -0
- package/dist/cjs/ultramodern-workspace/fs-io.cjs +117 -0
- package/dist/cjs/ultramodern-workspace/generation-result.cjs +1 -1
- package/dist/cjs/ultramodern-workspace/index.cjs +4 -0
- package/dist/cjs/ultramodern-workspace/mf-validation.cjs +572 -0
- package/dist/cjs/ultramodern-workspace/module-federation.cjs +14 -0
- package/dist/cjs/ultramodern-workspace/package-json.cjs +26 -12
- package/dist/cjs/ultramodern-workspace/public-api.cjs +4 -0
- package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +74 -44
- package/dist/cjs/ultramodern-workspace/write-workspace.cjs +55 -15
- package/dist/esm/index.js +36 -3
- package/dist/esm/locale/en.js +10 -0
- package/dist/esm/locale/zh.js +10 -0
- package/dist/esm/ultramodern-tooling/commands.js +132 -0
- package/dist/esm/ultramodern-tooling/config.js +196 -0
- package/dist/esm/ultramodern-workspace/add-vertical.js +65 -29
- package/dist/esm/ultramodern-workspace/bridge-config.js +270 -0
- package/dist/esm/ultramodern-workspace/codesmith.js +1 -0
- package/dist/esm/ultramodern-workspace/contracts.js +122 -608
- package/dist/esm/ultramodern-workspace/descriptors.js +2 -1
- package/dist/esm/ultramodern-workspace/fs-io.js +116 -2
- package/dist/esm/ultramodern-workspace/generation-result.js +2 -2
- package/dist/esm/ultramodern-workspace/index.js +1 -0
- package/dist/esm/ultramodern-workspace/mf-validation.js +517 -0
- package/dist/esm/ultramodern-workspace/module-federation.js +14 -0
- package/dist/esm/ultramodern-workspace/package-json.js +26 -12
- package/dist/esm/ultramodern-workspace/public-api.js +1 -0
- package/dist/esm/ultramodern-workspace/workspace-scripts.js +75 -27
- package/dist/esm/ultramodern-workspace/write-workspace.js +56 -19
- package/dist/esm-node/index.js +36 -3
- package/dist/esm-node/locale/en.js +10 -0
- package/dist/esm-node/locale/zh.js +10 -0
- package/dist/esm-node/ultramodern-tooling/commands.js +133 -0
- package/dist/esm-node/ultramodern-tooling/config.js +197 -0
- package/dist/esm-node/ultramodern-workspace/add-vertical.js +65 -29
- package/dist/esm-node/ultramodern-workspace/bridge-config.js +271 -0
- package/dist/esm-node/ultramodern-workspace/codesmith.js +1 -0
- package/dist/esm-node/ultramodern-workspace/contracts.js +122 -608
- package/dist/esm-node/ultramodern-workspace/descriptors.js +2 -1
- package/dist/esm-node/ultramodern-workspace/fs-io.js +116 -2
- package/dist/esm-node/ultramodern-workspace/generation-result.js +2 -2
- package/dist/esm-node/ultramodern-workspace/index.js +1 -0
- package/dist/esm-node/ultramodern-workspace/mf-validation.js +518 -0
- package/dist/esm-node/ultramodern-workspace/module-federation.js +14 -0
- package/dist/esm-node/ultramodern-workspace/package-json.js +26 -12
- package/dist/esm-node/ultramodern-workspace/public-api.js +1 -0
- package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +75 -27
- package/dist/esm-node/ultramodern-workspace/write-workspace.js +56 -19
- package/dist/types/locale/en.d.ts +10 -0
- package/dist/types/locale/index.d.ts +20 -0
- package/dist/types/locale/zh.d.ts +10 -0
- package/dist/types/ultramodern-tooling/commands.d.ts +1 -0
- package/dist/types/ultramodern-tooling/config.d.ts +43 -0
- package/dist/types/ultramodern-workspace/add-vertical.d.ts +5 -2
- package/dist/types/ultramodern-workspace/bridge-config.d.ts +64 -0
- package/dist/types/ultramodern-workspace/codesmith.d.ts +1 -0
- package/dist/types/ultramodern-workspace/contracts.d.ts +2 -17
- package/dist/types/ultramodern-workspace/descriptors.d.ts +1 -0
- package/dist/types/ultramodern-workspace/fs-io.d.ts +1 -0
- package/dist/types/ultramodern-workspace/index.d.ts +2 -0
- package/dist/types/ultramodern-workspace/mf-validation.d.ts +27 -0
- package/dist/types/ultramodern-workspace/package-json.d.ts +4 -3
- package/dist/types/ultramodern-workspace/public-api.d.ts +2 -0
- package/dist/types/ultramodern-workspace/types.d.ts +2 -0
- package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +1 -7
- package/dist/types/ultramodern-workspace/write-workspace.d.ts +4 -2
- package/package.json +5 -3
- package/template-workspace/{.agents → .codex}/skills-lock.json +12 -12
- package/template-workspace/.gitignore.handlebars +3 -0
- package/template-workspace/AGENTS.md.handlebars +11 -5
- package/template-workspace/README.md.handlebars +15 -12
- package/template-workspace/oxfmt.config.ts +1 -0
- package/template-workspace/oxlint.config.ts +1 -0
- package/template-workspace/scripts/bootstrap-agent-skills.mjs +77 -67
- package/templates/workspace-scripts/assert-mf-types.mjs.handlebars +56 -3
- package/templates/workspace-scripts/generate-public-surface-assets.mjs +239 -4
- package/templates/workspace-scripts/proof-cloudflare-version.mjs +282 -4
- package/templates/workspace-scripts/ultramodern-performance-readiness.mjs +172 -1
- package/templates/workspace-scripts/ultramodern-typecheck.mjs +4 -2
- package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +783 -26
- /package/template-workspace/{.agents → .codex}/rstackjs-agent-skills-LICENSE +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsbuild-best-practices/SKILL.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/SKILL.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/command-map.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/common-analysis-patterns.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor-common.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor-rspack.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor-webpack.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/rsdoctor-data-types.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rslib-best-practices/SKILL.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rslib-modern-package/SKILL.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rspack-best-practices/SKILL.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/SKILL.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/references/bottlenecks.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/references/tracing-guide.md +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/scripts/analyze_trace.js +0 -0
- /package/template-workspace/{.agents → .codex}/skills/rstest-best-practices/SKILL.md +0 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import node_fs from "node:fs";
|
|
3
|
+
import node_path from "node:path";
|
|
4
|
+
import { normalizeUltramodernBridgeConfig } from "../ultramodern-workspace/bridge-config.js";
|
|
5
|
+
import { GENERATED_CONTRACT_PATH, ULTRAMODERN_CONFIG_PATH, createNeutralOwnership, shellApp } from "../ultramodern-workspace/descriptors.js";
|
|
6
|
+
import { toKebabCase } from "../ultramodern-workspace/naming.js";
|
|
7
|
+
const PACKAGE_SOURCE_METADATA_PATH = '.modernjs/ultramodern-package-source.json';
|
|
8
|
+
const DEVELOPMENT_OVERLAY_PATH = 'topology/local-overlays/development.json';
|
|
9
|
+
function readJsonObject(filePath) {
|
|
10
|
+
const value = JSON.parse(node_fs.readFileSync(filePath, 'utf-8'));
|
|
11
|
+
if (null === value || 'object' != typeof value || Array.isArray(value)) throw new Error(`UltraModern config must contain a JSON object: ${filePath}`);
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
function readOptionalJsonObject(filePath) {
|
|
15
|
+
return node_fs.existsSync(filePath) ? readJsonObject(filePath) : {};
|
|
16
|
+
}
|
|
17
|
+
function packageScopeFromRoot(workspaceRoot) {
|
|
18
|
+
const rootPackage = readOptionalJsonObject(node_path.join(workspaceRoot, 'package.json'));
|
|
19
|
+
return 'string' == typeof rootPackage.name && rootPackage.name.length > 0 ? rootPackage.name : node_path.basename(workspaceRoot);
|
|
20
|
+
}
|
|
21
|
+
function packageSourceFromMetadata(workspaceRoot) {
|
|
22
|
+
const metadataPath = node_path.join(workspaceRoot, PACKAGE_SOURCE_METADATA_PATH);
|
|
23
|
+
if (!node_fs.existsSync(metadataPath)) return;
|
|
24
|
+
const metadata = readJsonObject(metadataPath);
|
|
25
|
+
const aliases = metadata.modernPackages?.aliases ?? {};
|
|
26
|
+
const firstAlias = Object.values(aliases).find((value)=>'string' == typeof value);
|
|
27
|
+
const firstPackage = Object.keys(aliases)[0];
|
|
28
|
+
const aliasScope = firstAlias?.match(/^@([^/]+)\//)?.[1];
|
|
29
|
+
const unscopedName = firstPackage?.split('/').at(-1) ?? '';
|
|
30
|
+
const aliasUnscopedName = firstAlias?.split('/').at(-1) ?? '';
|
|
31
|
+
const aliasPackageNamePrefix = aliasUnscopedName && unscopedName && aliasUnscopedName.endsWith(unscopedName) ? aliasUnscopedName.slice(0, -unscopedName.length) : void 0;
|
|
32
|
+
return {
|
|
33
|
+
strategy: 'install' === metadata.strategy ? 'install' : 'workspace',
|
|
34
|
+
modernPackageVersion: 'string' == typeof metadata.modernPackages?.specifier ? metadata.modernPackages.specifier : 'workspace:*',
|
|
35
|
+
registry: 'string' == typeof metadata.modernPackages?.registry ? metadata.modernPackages.registry : void 0,
|
|
36
|
+
aliasScope,
|
|
37
|
+
aliasPackageNamePrefix
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function readOverlayPorts(workspaceRoot) {
|
|
41
|
+
const overlayPath = node_path.join(workspaceRoot, DEVELOPMENT_OVERLAY_PATH);
|
|
42
|
+
if (!node_fs.existsSync(overlayPath)) return {};
|
|
43
|
+
const overlay = readJsonObject(overlayPath);
|
|
44
|
+
const ports = overlay.ports;
|
|
45
|
+
if (null === ports || 'object' != typeof ports || Array.isArray(ports)) return {};
|
|
46
|
+
return Object.fromEntries(Object.entries(ports).filter((entry)=>'number' == typeof entry[1]));
|
|
47
|
+
}
|
|
48
|
+
function normalizeCompactConfig(workspaceRoot, sourcePath, config) {
|
|
49
|
+
const packageSource = config.packageSource && 'object' == typeof config.packageSource ? {
|
|
50
|
+
strategy: 'install' === config.packageSource.strategy ? 'install' : 'workspace',
|
|
51
|
+
modernPackageVersion: 'string' == typeof config.packageSource.modernPackageVersion ? config.packageSource.modernPackageVersion : 'workspace:*',
|
|
52
|
+
registry: 'string' == typeof config.packageSource.registry ? config.packageSource.registry : void 0,
|
|
53
|
+
aliasScope: 'string' == typeof config.packageSource.aliasScope ? config.packageSource.aliasScope : void 0,
|
|
54
|
+
aliasPackageNamePrefix: 'string' == typeof config.packageSource.aliasPackageNamePrefix ? config.packageSource.aliasPackageNamePrefix : void 0
|
|
55
|
+
} : packageSourceFromMetadata(workspaceRoot);
|
|
56
|
+
return {
|
|
57
|
+
schemaVersion: 'number' == typeof config.schemaVersion ? config.schemaVersion : 1,
|
|
58
|
+
profile: 'string' == typeof config.profile ? config.profile : void 0,
|
|
59
|
+
source: 'compact',
|
|
60
|
+
sourcePath,
|
|
61
|
+
workspace: {
|
|
62
|
+
packageScope: 'string' == typeof config.workspace?.packageScope ? config.workspace.packageScope : packageScopeFromRoot(workspaceRoot)
|
|
63
|
+
},
|
|
64
|
+
packageSource,
|
|
65
|
+
features: {
|
|
66
|
+
tailwind: config.features?.tailwind !== false
|
|
67
|
+
},
|
|
68
|
+
bridge: normalizeUltramodernBridgeConfig(config.bridge),
|
|
69
|
+
topology: {
|
|
70
|
+
apps: Array.isArray(config.topology?.apps) ? config.topology.apps.map((app)=>({
|
|
71
|
+
id: String(app.id),
|
|
72
|
+
kind: 'vertical' === app.kind ? 'vertical' : 'shell',
|
|
73
|
+
path: 'string' == typeof app.path ? app.path : '.',
|
|
74
|
+
package: 'string' == typeof app.package ? app.package : void 0,
|
|
75
|
+
packageSuffix: 'string' == typeof app.packageSuffix ? app.packageSuffix : void 0,
|
|
76
|
+
displayName: 'string' == typeof app.displayName ? app.displayName : void 0,
|
|
77
|
+
domain: 'string' == typeof app.domain ? app.domain : void 0,
|
|
78
|
+
port: 'number' == typeof app.port ? app.port : void 0,
|
|
79
|
+
portEnv: 'string' == typeof app.portEnv ? app.portEnv : void 0,
|
|
80
|
+
moduleFederation: app.moduleFederation && 'object' == typeof app.moduleFederation ? {
|
|
81
|
+
role: 'remote' === app.moduleFederation.role ? 'remote' : 'host',
|
|
82
|
+
name: 'string' == typeof app.moduleFederation.name ? app.moduleFederation.name : void 0,
|
|
83
|
+
exposes: Array.isArray(app.moduleFederation.exposes) ? app.moduleFederation.exposes.filter((expose)=>'string' == typeof expose) : void 0,
|
|
84
|
+
verticalRefs: Array.isArray(app.moduleFederation.verticalRefs) ? app.moduleFederation.verticalRefs.filter((ref)=>'string' == typeof ref) : void 0,
|
|
85
|
+
hostOnly: true === app.moduleFederation.hostOnly,
|
|
86
|
+
noExposes: true === app.moduleFederation.noExposes
|
|
87
|
+
} : void 0,
|
|
88
|
+
effectApi: app.effectApi && 'object' == typeof app.effectApi ? {
|
|
89
|
+
stem: 'string' == typeof app.effectApi.stem ? app.effectApi.stem : String(app.id),
|
|
90
|
+
prefix: 'string' == typeof app.effectApi.prefix ? app.effectApi.prefix : `/${String(app.id)}-api`,
|
|
91
|
+
consumedBy: Array.isArray(app.effectApi.consumedBy) ? app.effectApi.consumedBy.filter((consumer)=>'string' == typeof consumer) : [
|
|
92
|
+
shellApp.id,
|
|
93
|
+
String(app.id)
|
|
94
|
+
]
|
|
95
|
+
} : void 0
|
|
96
|
+
})) : []
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function adaptLegacyContract(workspaceRoot, sourcePath, contract) {
|
|
101
|
+
const ports = readOverlayPorts(workspaceRoot);
|
|
102
|
+
const apps = Array.isArray(contract.apps) ? contract.apps : [];
|
|
103
|
+
const shell = apps.find((app)=>app?.id === shellApp.id);
|
|
104
|
+
return {
|
|
105
|
+
schemaVersion: 'number' == typeof contract.schemaVersion ? contract.schemaVersion : 1,
|
|
106
|
+
profile: 'string' == typeof contract.profile ? contract.profile : void 0,
|
|
107
|
+
source: 'legacy',
|
|
108
|
+
sourcePath,
|
|
109
|
+
workspace: {
|
|
110
|
+
packageScope: packageScopeFromRoot(workspaceRoot)
|
|
111
|
+
},
|
|
112
|
+
packageSource: packageSourceFromMetadata(workspaceRoot),
|
|
113
|
+
features: {
|
|
114
|
+
tailwind: shell?.styling?.tailwind !== false
|
|
115
|
+
},
|
|
116
|
+
topology: {
|
|
117
|
+
apps: apps.map((app)=>{
|
|
118
|
+
const id = String(app.id);
|
|
119
|
+
const appPath = 'string' == typeof app.path ? app.path : id === shellApp.id ? shellApp.directory : `verticals/${toKebabCase(id)}`;
|
|
120
|
+
const domain = 'string' == typeof app.i18n?.namespace && 'shell' !== app.i18n.namespace ? app.i18n.namespace : appPath.split('/').at(-1);
|
|
121
|
+
return {
|
|
122
|
+
id,
|
|
123
|
+
kind: 'vertical' === app.kind ? 'vertical' : 'shell',
|
|
124
|
+
path: appPath,
|
|
125
|
+
package: 'string' == typeof app.package ? app.package : void 0,
|
|
126
|
+
packageSuffix: 'string' == typeof app.package ? app.package.split('/').at(-1) : appPath.split('/').at(-1),
|
|
127
|
+
displayName: id === shellApp.id ? shellApp.displayName : void 0,
|
|
128
|
+
domain,
|
|
129
|
+
port: ports[id],
|
|
130
|
+
moduleFederation: app.moduleFederation && 'object' == typeof app.moduleFederation ? {
|
|
131
|
+
role: 'vertical' === app.kind ? 'remote' : 'host',
|
|
132
|
+
name: 'string' == typeof app.moduleFederation.name ? app.moduleFederation.name : void 0,
|
|
133
|
+
exposes: Array.isArray(app.moduleFederation.exposes) ? app.moduleFederation.exposes.filter((expose)=>'string' == typeof expose) : void 0,
|
|
134
|
+
verticalRefs: Array.isArray(app.moduleFederation.verticalRefs) ? app.moduleFederation.verticalRefs.filter((ref)=>'string' == typeof ref) : void 0,
|
|
135
|
+
hostOnly: 'vertical' !== app.kind
|
|
136
|
+
} : void 0,
|
|
137
|
+
effectApi: app.effect && 'object' == typeof app.effect ? {
|
|
138
|
+
stem: 'string' == typeof app.effect.prefix ? app.effect.prefix.split('/').filter(Boolean).at(-1) ?? domain ?? id : domain ?? id,
|
|
139
|
+
prefix: 'string' == typeof app.effect.prefix ? app.effect.prefix : `/${domain ?? id}-api`,
|
|
140
|
+
consumedBy: [
|
|
141
|
+
shellApp.id,
|
|
142
|
+
id
|
|
143
|
+
]
|
|
144
|
+
} : void 0
|
|
145
|
+
};
|
|
146
|
+
})
|
|
147
|
+
},
|
|
148
|
+
legacyContract: contract
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function readUltramodernConfig(workspaceRoot = process.cwd()) {
|
|
152
|
+
const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
|
|
153
|
+
if (node_fs.existsSync(compactPath)) return normalizeCompactConfig(workspaceRoot, compactPath, readJsonObject(compactPath));
|
|
154
|
+
const legacyPath = node_path.join(workspaceRoot, GENERATED_CONTRACT_PATH);
|
|
155
|
+
if (node_fs.existsSync(legacyPath)) return adaptLegacyContract(workspaceRoot, legacyPath, readJsonObject(legacyPath));
|
|
156
|
+
throw new Error(`Missing UltraModern config. Expected ${ULTRAMODERN_CONFIG_PATH} or ${GENERATED_CONTRACT_PATH}.`);
|
|
157
|
+
}
|
|
158
|
+
function workspaceAppsFromToolingConfig(config) {
|
|
159
|
+
return config.topology.apps.map((app)=>{
|
|
160
|
+
if ('shell' === app.kind) return {
|
|
161
|
+
...shellApp,
|
|
162
|
+
directory: app.path,
|
|
163
|
+
packageSuffix: app.packageSuffix ?? shellApp.packageSuffix,
|
|
164
|
+
displayName: app.displayName ?? shellApp.displayName,
|
|
165
|
+
port: app.port ?? shellApp.port,
|
|
166
|
+
portEnv: app.portEnv ?? shellApp.portEnv,
|
|
167
|
+
mfName: app.moduleFederation?.name ?? shellApp.mfName,
|
|
168
|
+
verticalRefs: app.moduleFederation?.verticalRefs ?? []
|
|
169
|
+
};
|
|
170
|
+
const domain = app.domain ?? app.id;
|
|
171
|
+
const packageSuffix = app.packageSuffix ?? domain;
|
|
172
|
+
const exposes = Object.fromEntries((app.moduleFederation?.exposes ?? []).map((expose)=>[
|
|
173
|
+
expose,
|
|
174
|
+
'./Route' === expose ? './src/federation-entry.tsx' : './Widget' === expose ? `./src/components/${domain}-widget.tsx` : ''
|
|
175
|
+
]));
|
|
176
|
+
return {
|
|
177
|
+
id: app.id,
|
|
178
|
+
directory: app.path,
|
|
179
|
+
packageSuffix,
|
|
180
|
+
displayName: app.displayName ?? `${domain} Vertical`,
|
|
181
|
+
kind: 'vertical',
|
|
182
|
+
domain,
|
|
183
|
+
portEnv: app.portEnv ?? `VERTICAL_${domain.replace(/[^a-zA-Z0-9]+/g, '_').toUpperCase()}_PORT`,
|
|
184
|
+
port: app.port ?? 0,
|
|
185
|
+
mfName: app.moduleFederation?.name ?? app.id,
|
|
186
|
+
exposes,
|
|
187
|
+
...app.moduleFederation?.verticalRefs ? {
|
|
188
|
+
verticalRefs: app.moduleFederation.verticalRefs
|
|
189
|
+
} : {},
|
|
190
|
+
...app.effectApi ? {
|
|
191
|
+
effectApi: app.effectApi
|
|
192
|
+
} : {},
|
|
193
|
+
ownership: createNeutralOwnership(app.id)
|
|
194
|
+
};
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
export { readUltramodernConfig, workspaceAppsFromToolingConfig };
|
|
@@ -3,12 +3,12 @@ import node_fs from "node:fs";
|
|
|
3
3
|
import node_os from "node:os";
|
|
4
4
|
import node_path from "node:path";
|
|
5
5
|
import { WORKSPACE_PACKAGE_VERSION } from "../ultramodern-package-source.js";
|
|
6
|
+
import { readUltramodernConfig } from "../ultramodern-tooling/config.js";
|
|
6
7
|
import { createAppEnvDts, createAppRuntimeConfig, createShellFrameComponent } from "./app-files.js";
|
|
7
|
-
import { createGeneratedContract } from "./contracts.js";
|
|
8
8
|
import { createShellPage, createShellRemoteComponents } from "./demo-components.js";
|
|
9
|
-
import { GENERATED_CONTRACT_PATH, appHasEffectApi, appI18nNamespace, createModuleFederationRemoteContracts, createNeutralOwnership, createRemoteManifestEnv, createShellHost, createVerticalDescriptor, effectApiPrefix, remoteDependencyAlias, shellApp, zephyrRemoteDependency } from "./descriptors.js";
|
|
9
|
+
import { GENERATED_CONTRACT_PATH, ULTRAMODERN_CONFIG_PATH, appHasEffectApi, appI18nNamespace, createModuleFederationRemoteContracts, createNeutralOwnership, createRemoteManifestEnv, createShellHost, createVerticalDescriptor, effectApiPrefix, remoteDependencyAlias, shellApp, zephyrRemoteDependency } from "./descriptors.js";
|
|
10
10
|
import { createShellEffectClient, effectApiTopologyMetadata } from "./effect-api.js";
|
|
11
|
-
import { readJsonFile, writeFileReplacing, writeJsonFile } from "./fs-io.js";
|
|
11
|
+
import { formatGeneratedWorkspaceFiles, readJsonFile, writeFileReplacing, writeJsonFile } from "./fs-io.js";
|
|
12
12
|
import { createFileSnapshot, createGenerationResult, diffFileSnapshots } from "./generation-result.js";
|
|
13
13
|
import { createAppPublicLocaleMessages } from "./locales.js";
|
|
14
14
|
import { createShellModuleFederationConfig } from "./module-federation.js";
|
|
@@ -20,7 +20,7 @@ import { createCloudflareDeployContract } from "./policy.js";
|
|
|
20
20
|
import { createPublicWebAppArtifacts, rewriteWorkspaceAssetsForApp } from "./public-surface.js";
|
|
21
21
|
import { isRecord } from "./types.js";
|
|
22
22
|
import { writeGeneratedWorkspaceScripts } from "./workspace-scripts.js";
|
|
23
|
-
import { writeApp } from "./write-workspace.js";
|
|
23
|
+
import { createCompactUltramodernConfig, writeApp } from "./write-workspace.js";
|
|
24
24
|
const FIRST_VERTICAL_PORT = 4101;
|
|
25
25
|
const TOPOLOGY_PATH = 'topology/reference-topology.json';
|
|
26
26
|
const OWNERSHIP_PATH = 'topology/ownership.json';
|
|
@@ -33,7 +33,12 @@ function existingPackageSource(workspaceRoot, modernVersion, packageSource) {
|
|
|
33
33
|
modernVersion,
|
|
34
34
|
packageSource
|
|
35
35
|
});
|
|
36
|
-
const
|
|
36
|
+
const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
|
|
37
|
+
if (node_fs.existsSync(compactPath)) {
|
|
38
|
+
const compactConfig = readUltramodernConfig(workspaceRoot);
|
|
39
|
+
if (compactConfig.packageSource) return compactConfig.packageSource;
|
|
40
|
+
}
|
|
41
|
+
const metadataPath = node_path.join(workspaceRoot, PACKAGE_SOURCE_METADATA_PATH);
|
|
37
42
|
if (!node_fs.existsSync(metadataPath)) return resolvePackageSource({
|
|
38
43
|
targetDir: workspaceRoot,
|
|
39
44
|
packageName: node_path.basename(workspaceRoot),
|
|
@@ -56,6 +61,8 @@ function existingPackageSource(workspaceRoot, modernVersion, packageSource) {
|
|
|
56
61
|
};
|
|
57
62
|
}
|
|
58
63
|
function existingTailwindEnabled(workspaceRoot) {
|
|
64
|
+
const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
|
|
65
|
+
if (node_fs.existsSync(compactPath)) return readUltramodernConfig(workspaceRoot).features.tailwind;
|
|
59
66
|
const contractPath = node_path.join(workspaceRoot, GENERATED_CONTRACT_PATH);
|
|
60
67
|
if (!node_fs.existsSync(contractPath)) return true;
|
|
61
68
|
const contract = readJsonFile(contractPath);
|
|
@@ -63,6 +70,10 @@ function existingTailwindEnabled(workspaceRoot) {
|
|
|
63
70
|
const shell = apps.find((app)=>isRecord(app) && app.id === shellApp.id);
|
|
64
71
|
return shell?.styling && isRecord(shell.styling) ? false !== shell.styling.tailwind : true;
|
|
65
72
|
}
|
|
73
|
+
function existingBridgeConfig(workspaceRoot) {
|
|
74
|
+
const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
|
|
75
|
+
return node_fs.existsSync(compactPath) ? readUltramodernConfig(workspaceRoot).bridge : void 0;
|
|
76
|
+
}
|
|
66
77
|
function assertValidVerticalName(name) {
|
|
67
78
|
const normalized = toKebabCase(name);
|
|
68
79
|
if (!normalized || normalized !== name) throw new Error(`Invalid Vertical name "${name}". Use lowercase kebab-case.`);
|
|
@@ -75,17 +86,17 @@ function nextAvailablePort(ports) {
|
|
|
75
86
|
function assertCanCreate(workspaceRoot, relativePath) {
|
|
76
87
|
if (node_fs.existsSync(node_path.join(workspaceRoot, relativePath))) throw new Error(`Refusing to overwrite existing path: ${relativePath}`);
|
|
77
88
|
}
|
|
78
|
-
function updateRootWorkspaceScripts(workspaceRoot, scope, packageSource, remotes) {
|
|
89
|
+
function updateRootWorkspaceScripts(workspaceRoot, scope, packageSource, remotes, bridge) {
|
|
79
90
|
const packagePath = node_path.join(workspaceRoot, 'package.json');
|
|
80
91
|
const rootPackage = readJsonFile(packagePath);
|
|
81
|
-
const generatedRootPackage = createRootPackageJson(scope, packageSource, remotes);
|
|
92
|
+
const generatedRootPackage = createRootPackageJson(scope, packageSource, remotes, bridge);
|
|
82
93
|
rootPackage.scripts = generatedRootPackage.scripts;
|
|
83
94
|
writeJsonFile(packagePath, rootPackage);
|
|
84
95
|
}
|
|
85
|
-
function rewriteShellAppFiles(workspaceRoot, scope, packageSource, enableTailwind, remotes) {
|
|
96
|
+
function rewriteShellAppFiles(workspaceRoot, scope, packageSource, enableTailwind, remotes, bridge) {
|
|
86
97
|
const shellHost = createShellHost(remotes);
|
|
87
98
|
const publicWeb = createPublicWebAppArtifacts(shellHost);
|
|
88
|
-
writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/package.json`), createAppPackage(scope, shellHost, packageSource, enableTailwind, remotes));
|
|
99
|
+
writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/package.json`), createAppPackage(scope, shellHost, packageSource, enableTailwind, remotes, bridge));
|
|
89
100
|
writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/tsconfig.json`), createAppTsConfig(shellHost, remotes));
|
|
90
101
|
writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/tsconfig.mf-types.json`), createAppMfTypesTsConfig(shellHost));
|
|
91
102
|
writeFileReplacing(workspaceRoot, `${shellApp.directory}/src/modern-app-env.d.ts`, createAppEnvDts(shellHost, remotes));
|
|
@@ -204,8 +215,7 @@ function prepareAddUltramodernVertical(options) {
|
|
|
204
215
|
const topology = readRequiredJsonObject(topologyPath);
|
|
205
216
|
const ownership = readRequiredJsonObject(ownershipPath);
|
|
206
217
|
const overlay = readRequiredJsonObject(overlayPath);
|
|
207
|
-
|
|
208
|
-
readRequiredJsonObject(node_path.join(options.workspaceRoot, PACKAGE_SOURCE_METADATA_PATH));
|
|
218
|
+
readRequiredWorkspaceConfig(options.workspaceRoot);
|
|
209
219
|
assertOptionalJsonObject(topology.shell, 'topology.shell', topologyPath);
|
|
210
220
|
assertOptionalJsonArray(topology.verticals, 'topology.verticals', topologyPath);
|
|
211
221
|
assertOptionalJsonArray(ownership.owners, 'ownership.owners', ownershipPath);
|
|
@@ -216,6 +226,7 @@ function prepareAddUltramodernVertical(options) {
|
|
|
216
226
|
const scope = toPackageScope(String(rootPackage.name ?? node_path.basename(options.workspaceRoot)));
|
|
217
227
|
const packageSource = existingPackageSource(options.workspaceRoot, options.modernVersion, options.packageSource);
|
|
218
228
|
const enableTailwind = options.enableTailwind ?? existingTailwindEnabled(options.workspaceRoot);
|
|
229
|
+
const bridge = existingBridgeConfig(options.workspaceRoot);
|
|
219
230
|
const existingVerticals = verticalsFromTopology(topology, overlay.ports);
|
|
220
231
|
const port = nextAvailablePort(overlay.ports);
|
|
221
232
|
const vertical = createVerticalDescriptor(name, port);
|
|
@@ -243,6 +254,7 @@ function prepareAddUltramodernVertical(options) {
|
|
|
243
254
|
overlay,
|
|
244
255
|
packageSource,
|
|
245
256
|
enableTailwind,
|
|
257
|
+
bridge,
|
|
246
258
|
vertical,
|
|
247
259
|
updatedVerticals
|
|
248
260
|
};
|
|
@@ -253,6 +265,12 @@ function readRequiredJsonObject(filePath) {
|
|
|
253
265
|
if (!isRecord(value)) throw new Error(`UltraModern workspace file must contain a JSON object: ${filePath}`);
|
|
254
266
|
return value;
|
|
255
267
|
}
|
|
268
|
+
function readRequiredWorkspaceConfig(workspaceRoot) {
|
|
269
|
+
const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
|
|
270
|
+
if (node_fs.existsSync(compactPath)) return void readRequiredJsonObject(compactPath);
|
|
271
|
+
readRequiredJsonObject(node_path.join(workspaceRoot, GENERATED_CONTRACT_PATH));
|
|
272
|
+
readRequiredJsonObject(node_path.join(workspaceRoot, PACKAGE_SOURCE_METADATA_PATH));
|
|
273
|
+
}
|
|
256
274
|
function assertOptionalJsonObject(value, label, filePath) {
|
|
257
275
|
if (void 0 !== value && !isRecord(value)) throw new Error(`${label} in ${filePath} must be a JSON object`);
|
|
258
276
|
}
|
|
@@ -357,7 +375,7 @@ function createVerticalPlan(preflight, result) {
|
|
|
357
375
|
shellDependencyChanges: createShellDependencyChanges(scope, vertical),
|
|
358
376
|
generatedContractChanges: [
|
|
359
377
|
{
|
|
360
|
-
path:
|
|
378
|
+
path: ULTRAMODERN_CONFIG_PATH,
|
|
361
379
|
addedAppIds: [
|
|
362
380
|
vertical.id
|
|
363
381
|
],
|
|
@@ -444,9 +462,9 @@ function createDryRunJsonMutations(preflight, manifestUrl) {
|
|
|
444
462
|
description: 'Keep shell Module Federation DTS compilation scoped'
|
|
445
463
|
},
|
|
446
464
|
{
|
|
447
|
-
path:
|
|
448
|
-
pointer: '/apps',
|
|
449
|
-
description: `Regenerate
|
|
465
|
+
path: ULTRAMODERN_CONFIG_PATH,
|
|
466
|
+
pointer: '/topology/apps',
|
|
467
|
+
description: `Regenerate compact config with ${vertical.id}`
|
|
450
468
|
}
|
|
451
469
|
];
|
|
452
470
|
}
|
|
@@ -470,8 +488,8 @@ function createShellDependencyChanges(scope, vertical) {
|
|
|
470
488
|
}
|
|
471
489
|
function addUltramodernVertical(options) {
|
|
472
490
|
const beforeFiles = createFileSnapshot(options.workspaceRoot);
|
|
473
|
-
const { scope, topologyPath, ownershipPath, overlayPath, topology, ownership, overlay, packageSource, enableTailwind, vertical, updatedVerticals } = prepareAddUltramodernVertical(options);
|
|
474
|
-
writeApp(options.workspaceRoot, scope, vertical, packageSource, enableTailwind);
|
|
491
|
+
const { scope, topologyPath, ownershipPath, overlayPath, topology, ownership, overlay, packageSource, enableTailwind, bridge, vertical, updatedVerticals } = prepareAddUltramodernVertical(options);
|
|
492
|
+
writeApp(options.workspaceRoot, scope, vertical, packageSource, enableTailwind, updatedVerticals, bridge);
|
|
475
493
|
topology.shell ??= {};
|
|
476
494
|
topology.shell.verticalRefs ??= [];
|
|
477
495
|
topology.shell.verticalRefs.push(vertical.id);
|
|
@@ -494,18 +512,18 @@ function addUltramodernVertical(options) {
|
|
|
494
512
|
writeJsonFile(topologyPath, topology);
|
|
495
513
|
writeJsonFile(ownershipPath, ownership);
|
|
496
514
|
writeJsonFile(overlayPath, overlay);
|
|
497
|
-
writeJsonFile(node_path.join(options.workspaceRoot,
|
|
515
|
+
writeJsonFile(node_path.join(options.workspaceRoot, ULTRAMODERN_CONFIG_PATH), createCompactUltramodernConfig(scope, options.modernVersion, packageSource, [
|
|
498
516
|
{
|
|
499
517
|
...shellApp,
|
|
500
518
|
verticalRefs: updatedVerticals.map((vertical)=>vertical.id)
|
|
501
519
|
},
|
|
502
520
|
...updatedVerticals
|
|
503
|
-
], enableTailwind));
|
|
504
|
-
rewriteShellAppFiles(options.workspaceRoot, scope, packageSource, enableTailwind, updatedVerticals);
|
|
521
|
+
], enableTailwind, bridge));
|
|
522
|
+
rewriteShellAppFiles(options.workspaceRoot, scope, packageSource, enableTailwind, updatedVerticals, bridge);
|
|
505
523
|
writeGeneratedWorkspaceScripts(options.workspaceRoot, scope, enableTailwind, updatedVerticals);
|
|
506
524
|
addShellZephyrDependency(options.workspaceRoot, scope, vertical);
|
|
507
525
|
addShellWorkspaceDependency(options.workspaceRoot, scope, vertical);
|
|
508
|
-
updateRootWorkspaceScripts(options.workspaceRoot, scope, packageSource, updatedVerticals);
|
|
526
|
+
updateRootWorkspaceScripts(options.workspaceRoot, scope, packageSource, updatedVerticals, bridge);
|
|
509
527
|
writeJsonFile(node_path.join(options.workspaceRoot, 'tsconfig.json'), createRootTsConfig([
|
|
510
528
|
{
|
|
511
529
|
...shellApp,
|
|
@@ -513,9 +531,9 @@ function addUltramodernVertical(options) {
|
|
|
513
531
|
},
|
|
514
532
|
...updatedVerticals
|
|
515
533
|
]));
|
|
516
|
-
const
|
|
517
|
-
const
|
|
518
|
-
const
|
|
534
|
+
const preliminaryAfterFiles = createFileSnapshot(options.workspaceRoot);
|
|
535
|
+
const preliminaryDiff = diffFileSnapshots(beforeFiles, preliminaryAfterFiles);
|
|
536
|
+
const preliminaryResult = createGenerationResult({
|
|
519
537
|
operation: 'vertical',
|
|
520
538
|
workspaceRoot: options.workspaceRoot,
|
|
521
539
|
packageScope: scope,
|
|
@@ -523,14 +541,32 @@ function addUltramodernVertical(options) {
|
|
|
523
541
|
createdApps: [
|
|
524
542
|
vertical
|
|
525
543
|
],
|
|
526
|
-
createdPaths,
|
|
527
|
-
rewrittenPaths
|
|
544
|
+
createdPaths: preliminaryDiff.createdPaths,
|
|
545
|
+
rewrittenPaths: preliminaryDiff.rewrittenPaths
|
|
528
546
|
});
|
|
529
547
|
runCodeSmithOverlays({
|
|
530
548
|
workspaceRoot: options.workspaceRoot,
|
|
531
549
|
overlays: options.overlays,
|
|
532
|
-
result
|
|
550
|
+
result: preliminaryResult
|
|
551
|
+
});
|
|
552
|
+
const afterOverlaysFiles = createFileSnapshot(options.workspaceRoot);
|
|
553
|
+
const changedPaths = diffFileSnapshots(beforeFiles, afterOverlaysFiles);
|
|
554
|
+
formatGeneratedWorkspaceFiles(options.workspaceRoot, [
|
|
555
|
+
...changedPaths.createdPaths,
|
|
556
|
+
...changedPaths.rewrittenPaths
|
|
557
|
+
]);
|
|
558
|
+
const afterFiles = createFileSnapshot(options.workspaceRoot);
|
|
559
|
+
const { createdPaths, rewrittenPaths } = diffFileSnapshots(beforeFiles, afterFiles);
|
|
560
|
+
return createGenerationResult({
|
|
561
|
+
operation: 'vertical',
|
|
562
|
+
workspaceRoot: options.workspaceRoot,
|
|
563
|
+
packageScope: scope,
|
|
564
|
+
packageSource,
|
|
565
|
+
createdApps: [
|
|
566
|
+
vertical
|
|
567
|
+
],
|
|
568
|
+
createdPaths,
|
|
569
|
+
rewrittenPaths
|
|
533
570
|
});
|
|
534
|
-
return result;
|
|
535
571
|
}
|
|
536
|
-
export { addShellWorkspaceDependency, addShellZephyrDependency, addUltramodernVertical, assertCanCreate, assertValidVerticalName, existingPackageSource, existingTailwindEnabled, nextAvailablePort, ownershipEntry, planUltramodernVertical, prepareAddUltramodernVertical, rewriteShellAppFiles, updateRootWorkspaceScripts, verticalTopologyEntry, verticalsFromTopology };
|
|
572
|
+
export { addShellWorkspaceDependency, addShellZephyrDependency, addUltramodernVertical, assertCanCreate, assertValidVerticalName, existingBridgeConfig, existingPackageSource, existingTailwindEnabled, nextAvailablePort, ownershipEntry, planUltramodernVertical, prepareAddUltramodernVertical, rewriteShellAppFiles, updateRootWorkspaceScripts, verticalTopologyEntry, verticalsFromTopology };
|