@bleedingdev/modern-js-create 3.4.0-ultramodern.2 → 3.4.0-ultramodern.3

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.
@@ -719,6 +719,7 @@ function createTemplateManifest(modernVersion, packageSource) {
719
719
  'pnpm-workspace.yaml',
720
720
  "scripts/**",
721
721
  'topology/**',
722
+ 'tsconfig.json',
722
723
  'tsconfig.base.json'
723
724
  ],
724
725
  deniedPaths: [
@@ -783,6 +784,7 @@ function createTemplateManifest(modernVersion, packageSource) {
783
784
  expectedCommands: [
784
785
  'mise install',
785
786
  'pnpm install',
787
+ 'pnpm run typecheck',
786
788
  'pnpm run i18n:boundaries',
787
789
  'pnpm run contract:check',
788
790
  'pnpm run performance:readiness'
@@ -49,8 +49,7 @@ import { VerticalShowcase } from '../vertical-components';
49
49
  import { ultramodernUiMarker } from '../../ultramodern-build';
50
50
 
51
51
  export default function ShellHome() {
52
- const { i18nInstance } = useModernI18n();
53
- const t = i18nInstance['t'].bind(i18nInstance);
52
+ const { t } = useModernI18n();
54
53
 
55
54
  return (
56
55
  <ShellFrame>
@@ -123,8 +122,7 @@ const loadRemoteComponent = (specifier: string) =>
123
122
 
124
123
  const createRemoteFallback = (specifier: string) =>
125
124
  ({ error }: { error: Error }) => {
126
- const { i18nInstance } = useModernI18n();
127
- const t = i18nInstance['t'].bind(i18nInstance);
125
+ const { t } = useModernI18n();
128
126
  const classification = classifyModuleFederationFallback(error);
129
127
  const telemetry = createModuleFederationFallbackTelemetry({
130
128
  appName: '${external_descriptors_cjs_namespaceObject.shellApp.id}',
@@ -206,8 +204,7 @@ const createHydratedRemote =
206
204
  ${hydratedExports}
207
205
 
208
206
  export const Header = () => {
209
- const { i18nInstance } = useModernI18n();
210
- const t = i18nInstance['t'].bind(i18nInstance);
207
+ const { t } = useModernI18n();
211
208
 
212
209
  return (
213
210
  <header className="${tw('flex min-w-0 flex-wrap items-center gap-x-8 gap-y-2 md:flex-1')}" data-modern-boundary-id="${external_descriptors_cjs_namespaceObject.shellApp.mfName}" data-modern-mf-expose="shell/Header">
@@ -217,8 +214,7 @@ const createHydratedRemote =
217
214
  };
218
215
 
219
216
  export const StatusBadge = () => {
220
- const { i18nInstance } = useModernI18n();
221
- const t = i18nInstance['t'].bind(i18nInstance);
217
+ const { t } = useModernI18n();
222
218
 
223
219
  return (
224
220
  <span className="${tw('inline-flex h-10 shrink-0 items-center justify-center rounded-full border border-stone-900/15 bg-white px-4 text-sm font-extrabold text-stone-950 shadow-lg shadow-stone-900/5')}">
@@ -228,8 +224,7 @@ export const StatusBadge = () => {
228
224
  };
229
225
 
230
226
  export const VerticalShowcase = () => {
231
- const { i18nInstance } = useModernI18n();
232
- const t = i18nInstance['t'].bind(i18nInstance);
227
+ const { t } = useModernI18n();
233
228
 
234
229
  if (widgetCount === 0) {
235
230
  return (
@@ -296,8 +291,7 @@ import { ultramodernUiMarker } from '../../ultramodern-build';
296
291
  ` : '';
297
292
  return `${effectBffImport}
298
293
  export default function ${(0, external_naming_cjs_namespaceObject.toPascalCase)(app.id)}Home() {
299
- const { i18nInstance, language, supportedLanguages } = useModernI18n();
300
- const t = i18nInstance['t'].bind(i18nInstance);
294
+ const { language, supportedLanguages, t } = useModernI18n();
301
295
  ${effectBffState} return (
302
296
  <main className="${tw('min-h-screen bg-um-canvas px-4 py-6 text-um-foreground sm:px-8')}">
303
297
  <UltramodernRouteHead />
@@ -343,8 +337,7 @@ function createRemoteEntry(app) {
343
337
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
344
338
 
345
339
  export default function ${(0, external_naming_cjs_namespaceObject.toPascalCase)(domain)}Route() {
346
- const { i18nInstance } = useModernI18n();
347
- const t = i18nInstance['t'].bind(i18nInstance);
340
+ const { t } = useModernI18n();
348
341
 
349
342
  return (
350
343
  <section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="./Route">
@@ -362,8 +355,7 @@ function createRemoteWidget(app) {
362
355
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
363
356
 
364
357
  export default function ${componentName}() {
365
- const { i18nInstance } = useModernI18n();
366
- const t = i18nInstance['t'].bind(i18nInstance);
358
+ const { t } = useModernI18n();
367
359
 
368
360
  return (
369
361
  <section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="./Widget">
@@ -382,8 +374,7 @@ function createRemoteExposeComponent(app, expose) {
382
374
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
383
375
 
384
376
  export default function ${componentName}() {
385
- const { i18nInstance } = useModernI18n();
386
- const t = i18nInstance['t'].bind(i18nInstance);
377
+ const { t } = useModernI18n();
387
378
 
388
379
  return (
389
380
  <section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="${expose}">
@@ -668,6 +668,7 @@ function createTemplateManifest(modernVersion, packageSource) {
668
668
  'pnpm-workspace.yaml',
669
669
  "scripts/**",
670
670
  'topology/**',
671
+ 'tsconfig.json',
671
672
  'tsconfig.base.json'
672
673
  ],
673
674
  deniedPaths: [
@@ -732,6 +733,7 @@ function createTemplateManifest(modernVersion, packageSource) {
732
733
  expectedCommands: [
733
734
  'mise install',
734
735
  'pnpm install',
736
+ 'pnpm run typecheck',
735
737
  'pnpm run i18n:boundaries',
736
738
  'pnpm run contract:check',
737
739
  'pnpm run performance:readiness'
@@ -10,8 +10,7 @@ import { VerticalShowcase } from '../vertical-components';
10
10
  import { ultramodernUiMarker } from '../../ultramodern-build';
11
11
 
12
12
  export default function ShellHome() {
13
- const { i18nInstance } = useModernI18n();
14
- const t = i18nInstance['t'].bind(i18nInstance);
13
+ const { t } = useModernI18n();
15
14
 
16
15
  return (
17
16
  <ShellFrame>
@@ -84,8 +83,7 @@ const loadRemoteComponent = (specifier: string) =>
84
83
 
85
84
  const createRemoteFallback = (specifier: string) =>
86
85
  ({ error }: { error: Error }) => {
87
- const { i18nInstance } = useModernI18n();
88
- const t = i18nInstance['t'].bind(i18nInstance);
86
+ const { t } = useModernI18n();
89
87
  const classification = classifyModuleFederationFallback(error);
90
88
  const telemetry = createModuleFederationFallbackTelemetry({
91
89
  appName: '${shellApp.id}',
@@ -167,8 +165,7 @@ const createHydratedRemote =
167
165
  ${hydratedExports}
168
166
 
169
167
  export const Header = () => {
170
- const { i18nInstance } = useModernI18n();
171
- const t = i18nInstance['t'].bind(i18nInstance);
168
+ const { t } = useModernI18n();
172
169
 
173
170
  return (
174
171
  <header className="${tw('flex min-w-0 flex-wrap items-center gap-x-8 gap-y-2 md:flex-1')}" data-modern-boundary-id="${shellApp.mfName}" data-modern-mf-expose="shell/Header">
@@ -178,8 +175,7 @@ const createHydratedRemote =
178
175
  };
179
176
 
180
177
  export const StatusBadge = () => {
181
- const { i18nInstance } = useModernI18n();
182
- const t = i18nInstance['t'].bind(i18nInstance);
178
+ const { t } = useModernI18n();
183
179
 
184
180
  return (
185
181
  <span className="${tw('inline-flex h-10 shrink-0 items-center justify-center rounded-full border border-stone-900/15 bg-white px-4 text-sm font-extrabold text-stone-950 shadow-lg shadow-stone-900/5')}">
@@ -189,8 +185,7 @@ export const StatusBadge = () => {
189
185
  };
190
186
 
191
187
  export const VerticalShowcase = () => {
192
- const { i18nInstance } = useModernI18n();
193
- const t = i18nInstance['t'].bind(i18nInstance);
188
+ const { t } = useModernI18n();
194
189
 
195
190
  if (widgetCount === 0) {
196
191
  return (
@@ -257,8 +252,7 @@ import { ultramodernUiMarker } from '../../ultramodern-build';
257
252
  ` : '';
258
253
  return `${effectBffImport}
259
254
  export default function ${toPascalCase(app.id)}Home() {
260
- const { i18nInstance, language, supportedLanguages } = useModernI18n();
261
- const t = i18nInstance['t'].bind(i18nInstance);
255
+ const { language, supportedLanguages, t } = useModernI18n();
262
256
  ${effectBffState} return (
263
257
  <main className="${tw('min-h-screen bg-um-canvas px-4 py-6 text-um-foreground sm:px-8')}">
264
258
  <UltramodernRouteHead />
@@ -304,8 +298,7 @@ function createRemoteEntry(app) {
304
298
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
305
299
 
306
300
  export default function ${toPascalCase(domain)}Route() {
307
- const { i18nInstance } = useModernI18n();
308
- const t = i18nInstance['t'].bind(i18nInstance);
301
+ const { t } = useModernI18n();
309
302
 
310
303
  return (
311
304
  <section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="./Route">
@@ -323,8 +316,7 @@ function createRemoteWidget(app) {
323
316
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
324
317
 
325
318
  export default function ${componentName}() {
326
- const { i18nInstance } = useModernI18n();
327
- const t = i18nInstance['t'].bind(i18nInstance);
319
+ const { t } = useModernI18n();
328
320
 
329
321
  return (
330
322
  <section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="./Widget">
@@ -343,8 +335,7 @@ function createRemoteExposeComponent(app, expose) {
343
335
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
344
336
 
345
337
  export default function ${componentName}() {
346
- const { i18nInstance } = useModernI18n();
347
- const t = i18nInstance['t'].bind(i18nInstance);
338
+ const { t } = useModernI18n();
348
339
 
349
340
  return (
350
341
  <section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="${expose}">
@@ -669,6 +669,7 @@ function createTemplateManifest(modernVersion, packageSource) {
669
669
  'pnpm-workspace.yaml',
670
670
  "scripts/**",
671
671
  'topology/**',
672
+ 'tsconfig.json',
672
673
  'tsconfig.base.json'
673
674
  ],
674
675
  deniedPaths: [
@@ -733,6 +734,7 @@ function createTemplateManifest(modernVersion, packageSource) {
733
734
  expectedCommands: [
734
735
  'mise install',
735
736
  'pnpm install',
737
+ 'pnpm run typecheck',
736
738
  'pnpm run i18n:boundaries',
737
739
  'pnpm run contract:check',
738
740
  'pnpm run performance:readiness'
@@ -11,8 +11,7 @@ import { VerticalShowcase } from '../vertical-components';
11
11
  import { ultramodernUiMarker } from '../../ultramodern-build';
12
12
 
13
13
  export default function ShellHome() {
14
- const { i18nInstance } = useModernI18n();
15
- const t = i18nInstance['t'].bind(i18nInstance);
14
+ const { t } = useModernI18n();
16
15
 
17
16
  return (
18
17
  <ShellFrame>
@@ -85,8 +84,7 @@ const loadRemoteComponent = (specifier: string) =>
85
84
 
86
85
  const createRemoteFallback = (specifier: string) =>
87
86
  ({ error }: { error: Error }) => {
88
- const { i18nInstance } = useModernI18n();
89
- const t = i18nInstance['t'].bind(i18nInstance);
87
+ const { t } = useModernI18n();
90
88
  const classification = classifyModuleFederationFallback(error);
91
89
  const telemetry = createModuleFederationFallbackTelemetry({
92
90
  appName: '${shellApp.id}',
@@ -168,8 +166,7 @@ const createHydratedRemote =
168
166
  ${hydratedExports}
169
167
 
170
168
  export const Header = () => {
171
- const { i18nInstance } = useModernI18n();
172
- const t = i18nInstance['t'].bind(i18nInstance);
169
+ const { t } = useModernI18n();
173
170
 
174
171
  return (
175
172
  <header className="${tw('flex min-w-0 flex-wrap items-center gap-x-8 gap-y-2 md:flex-1')}" data-modern-boundary-id="${shellApp.mfName}" data-modern-mf-expose="shell/Header">
@@ -179,8 +176,7 @@ const createHydratedRemote =
179
176
  };
180
177
 
181
178
  export const StatusBadge = () => {
182
- const { i18nInstance } = useModernI18n();
183
- const t = i18nInstance['t'].bind(i18nInstance);
179
+ const { t } = useModernI18n();
184
180
 
185
181
  return (
186
182
  <span className="${tw('inline-flex h-10 shrink-0 items-center justify-center rounded-full border border-stone-900/15 bg-white px-4 text-sm font-extrabold text-stone-950 shadow-lg shadow-stone-900/5')}">
@@ -190,8 +186,7 @@ export const StatusBadge = () => {
190
186
  };
191
187
 
192
188
  export const VerticalShowcase = () => {
193
- const { i18nInstance } = useModernI18n();
194
- const t = i18nInstance['t'].bind(i18nInstance);
189
+ const { t } = useModernI18n();
195
190
 
196
191
  if (widgetCount === 0) {
197
192
  return (
@@ -258,8 +253,7 @@ import { ultramodernUiMarker } from '../../ultramodern-build';
258
253
  ` : '';
259
254
  return `${effectBffImport}
260
255
  export default function ${toPascalCase(app.id)}Home() {
261
- const { i18nInstance, language, supportedLanguages } = useModernI18n();
262
- const t = i18nInstance['t'].bind(i18nInstance);
256
+ const { language, supportedLanguages, t } = useModernI18n();
263
257
  ${effectBffState} return (
264
258
  <main className="${tw('min-h-screen bg-um-canvas px-4 py-6 text-um-foreground sm:px-8')}">
265
259
  <UltramodernRouteHead />
@@ -305,8 +299,7 @@ function createRemoteEntry(app) {
305
299
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
306
300
 
307
301
  export default function ${toPascalCase(domain)}Route() {
308
- const { i18nInstance } = useModernI18n();
309
- const t = i18nInstance['t'].bind(i18nInstance);
302
+ const { t } = useModernI18n();
310
303
 
311
304
  return (
312
305
  <section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="./Route">
@@ -324,8 +317,7 @@ function createRemoteWidget(app) {
324
317
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
325
318
 
326
319
  export default function ${componentName}() {
327
- const { i18nInstance } = useModernI18n();
328
- const t = i18nInstance['t'].bind(i18nInstance);
320
+ const { t } = useModernI18n();
329
321
 
330
322
  return (
331
323
  <section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="./Widget">
@@ -344,8 +336,7 @@ function createRemoteExposeComponent(app, expose) {
344
336
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
345
337
 
346
338
  export default function ${componentName}() {
347
- const { i18nInstance } = useModernI18n();
348
- const t = i18nInstance['t'].bind(i18nInstance);
339
+ const { t } = useModernI18n();
349
340
 
350
341
  return (
351
342
  <section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="${expose}">
package/package.json CHANGED
@@ -21,7 +21,7 @@
21
21
  "engines": {
22
22
  "node": ">=20"
23
23
  },
24
- "version": "3.4.0-ultramodern.2",
24
+ "version": "3.4.0-ultramodern.3",
25
25
  "types": "./dist/types/index.d.ts",
26
26
  "main": "./dist/esm-node/index.js",
27
27
  "bin": {
@@ -75,7 +75,7 @@
75
75
  ],
76
76
  "dependencies": {
77
77
  "@modern-js/codesmith": "2.6.9",
78
- "@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.4.0-ultramodern.2"
78
+ "@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.4.0-ultramodern.3"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@rslib/core": "0.23.0",
@@ -97,6 +97,6 @@
97
97
  "test": "rm -rf dist && rslib build -c rslibconfig.mts && rstest --passWithNoTests"
98
98
  },
99
99
  "ultramodern": {
100
- "frameworkVersion": "3.4.0-ultramodern.2"
100
+ "frameworkVersion": "3.4.0-ultramodern.3"
101
101
  }
102
102
  }
@@ -14,6 +14,14 @@ minimumReleaseAgeExclude:
14
14
  - '@typescript/native-preview'
15
15
  - '@typescript/native-preview-*'
16
16
  - '@types/react'
17
+ - '@rsbuild/core'
18
+ - '@rsbuild/plugin-react'
19
+ - '@rsbuild/plugin-type-check'
20
+ - '@rspack/binding'
21
+ - '@rspack/binding-*'
22
+ - '@rspack/core'
23
+ - '@rspack/plugin-react-refresh'
24
+ - 'ts-checker-rspack-plugin'
17
25
  trustPolicy: no-downgrade
18
26
  trustPolicyIgnoreAfter: 1440
19
27
  blockExoticSubdeps: true
@@ -20,13 +20,30 @@ const cloneTimeoutMs = Number.parseInt(
20
20
 
21
21
  const readJson = filePath => JSON.parse(fs.readFileSync(filePath, 'utf-8'));
22
22
 
23
- const run = (command, args, options = {}) =>
24
- execFileSync(command, args, {
23
+ const commandOverrideEnv = {
24
+ gh: 'ULTRAMODERN_GH_BIN',
25
+ git: 'ULTRAMODERN_GIT_BIN',
26
+ lefthook: 'ULTRAMODERN_LEFTHOOK_BIN',
27
+ };
28
+
29
+ const resolveCommand = command => {
30
+ const overrideEnv = commandOverrideEnv[command];
31
+ return overrideEnv ? (process.env[overrideEnv] ?? command) : command;
32
+ };
33
+
34
+ const requiresCommandShell = command =>
35
+ process.platform === 'win32' && /\.(?:bat|cmd)$/iu.test(command);
36
+
37
+ const run = (command, args, options = {}) => {
38
+ const resolvedCommand = resolveCommand(command);
39
+ return execFileSync(resolvedCommand, args, {
25
40
  cwd: options.cwd ?? root,
26
41
  encoding: 'utf-8',
42
+ shell: requiresCommandShell(resolvedCommand),
27
43
  stdio: options.stdio ?? ['ignore', 'pipe', 'pipe'],
28
44
  timeout: options.timeout,
29
45
  });
46
+ };
30
47
 
31
48
  const commandExists = command => {
32
49
  try {
@@ -7,8 +7,7 @@ interface ShellFrameProps {
7
7
  }
8
8
 
9
9
  export default function ShellFrame({ children }: ShellFrameProps) {
10
- const { i18nInstance, language } = useModernI18n();
11
- const t = i18nInstance['t'].bind(i18nInstance);
10
+ const { language, t } = useModernI18n();
12
11
  const { alternates } = useLocalizedLocation();
13
12
 
14
13
  return (
@@ -104,8 +104,7 @@ const sanitiseJsonLd = (value: RouteJsonLd) =>
104
104
  JSON.stringify(value).replaceAll('<', '\\u003c');
105
105
 
106
106
  export const UltramodernRouteHead = () => {
107
- const { i18nInstance } = useModernI18n();
108
- const t = i18nInstance['t'].bind(i18nInstance);
107
+ const { language, t } = useModernI18n();
109
108
  const { canonical, alternates } = useLocalizedLocation();
110
109
  const route = resolveRouteMetadata(canonical);
111
110
  const title = route === undefined ? appName : t(route.titleKey);
@@ -116,7 +115,7 @@ export const UltramodernRouteHead = () => {
116
115
  const jsonLd = route?.jsonLd;
117
116
 
118
117
  return (
119
- <Helmet htmlAttributes={{ lang: i18nInstance.language ?? fallbackLanguage }}>
118
+ <Helmet htmlAttributes={{ lang: language ?? fallbackLanguage }}>
120
119
  <title>{title}</title>
121
120
  <meta content={description} name="description" />
122
121
  <meta content={indexable ? 'index, follow' : 'noindex, nofollow'} name="robots" />
@@ -140,7 +139,7 @@ export const UltramodernRouteHead = () => {
140
139
  <meta content={description} property="og:description" />
141
140
  <meta content={canonicalUrl} property="og:url" />
142
141
  <meta content="website" property="og:type" />
143
- <meta content={i18nInstance.language ?? fallbackLanguage} property="og:locale" />
142
+ <meta content={language ?? fallbackLanguage} property="og:locale" />
144
143
  <meta content="summary_large_image" name="twitter:card" />
145
144
  <meta content={title} name="twitter:title" />
146
145
  <meta content={description} name="twitter:description" />
@@ -390,6 +390,67 @@ const assertMicroVerticalContractGraph = ({
390
390
  );
391
391
  }
392
392
  };
393
+ const toPosixPath = value => value.split(path.sep).join('/');
394
+ const referenceFrom = (fromPath, toPath) => ({
395
+ path: toPosixPath(path.relative(fromPath, toPath)),
396
+ });
397
+ const sharedPackagePaths = [
398
+ 'packages/shared-contracts',
399
+ 'packages/shared-design-tokens',
400
+ ];
401
+ const assertTsConfigReferenceGraph = () => {
402
+ const rootTsConfig = readJson('tsconfig.json');
403
+ const shellTsConfig = readJson('apps/shell-super-app/tsconfig.json');
404
+ const expectedRootReferences = [
405
+ ...sharedPackagePaths,
406
+ 'apps/shell-super-app',
407
+ ...fullStackVerticals.map(vertical => vertical.path),
408
+ ].map(referencePath => ({ path: referencePath }));
409
+ const expectedShellReferences = [
410
+ ...sharedPackagePaths,
411
+ ...fullStackVerticals.map(vertical => vertical.path),
412
+ ].map(referencePath =>
413
+ referenceFrom('apps/shell-super-app', referencePath),
414
+ );
415
+
416
+ assertSameJson(
417
+ rootTsConfig.files,
418
+ [],
419
+ 'tsconfig.json files',
420
+ 'restore the generated root project-reference tsconfig',
421
+ );
422
+ assertSameJson(
423
+ rootTsConfig.references ?? [],
424
+ expectedRootReferences,
425
+ 'tsconfig.json references',
426
+ 'restore the generated root project-reference graph',
427
+ );
428
+ assertSameJson(
429
+ shellTsConfig.references ?? [],
430
+ expectedShellReferences,
431
+ 'apps/shell-super-app/tsconfig.json references',
432
+ 'restore the generated shell project-reference graph',
433
+ );
434
+
435
+ for (const vertical of fullStackVerticals) {
436
+ const verticalTsConfig = readJson(`${vertical.path}/tsconfig.json`);
437
+ const expectedVerticalReferences = [
438
+ ...sharedPackagePaths,
439
+ ...(vertical.verticalRefs ?? [])
440
+ .map(verticalRef =>
441
+ fullStackVerticals.find(candidate => candidate.id === verticalRef),
442
+ )
443
+ .filter(Boolean)
444
+ .map(referencedVertical => referencedVertical.path),
445
+ ].map(referencePath => referenceFrom(vertical.path, referencePath));
446
+ assertSameJson(
447
+ verticalTsConfig.references ?? [],
448
+ expectedVerticalReferences,
449
+ `${vertical.path}/tsconfig.json references`,
450
+ 'restore the generated MicroVertical project-reference graph',
451
+ );
452
+ }
453
+ };
393
454
  const packageJsonFiles = startDir => {
394
455
  const files = [];
395
456
  const queue = [startDir];
@@ -734,6 +795,7 @@ assertMicroVerticalContractGraph({
734
795
  overlay,
735
796
  shellPackage,
736
797
  });
798
+ assertTsConfigReferenceGraph();
737
799
 
738
800
  assert(rootPackage.private === true, 'Root package must be private');
739
801
  assert(typeof rootPackage.packageManager === 'string', 'Root must declare packageManager');