@aws/nx-plugin 0.37.1 → 0.38.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +2 -2
  2. package/generators.json +14 -14
  3. package/package.json +1 -1
  4. package/sdk/ts.d.ts +6 -6
  5. package/sdk/ts.js +8 -8
  6. package/sdk/ts.js.map +1 -1
  7. package/src/mcp-server/tools/general-guidance.js +1 -1
  8. package/src/preset/__snapshots__/generator.spec.ts.snap +2 -2
  9. package/src/py/fast-api/react/__snapshots__/generator.spec.ts.snap +0 -1
  10. package/src/py/fast-api/react/generator.js +1 -1
  11. package/src/py/fast-api/react/generator.js.map +1 -1
  12. package/src/py/project/generator.js +1 -1
  13. package/src/py/project/generator.js.map +1 -1
  14. package/src/trpc/react/__snapshots__/generator.spec.ts.snap +0 -1
  15. package/src/trpc/react/generator.js +1 -1
  16. package/src/trpc/react/generator.js.map +1 -1
  17. package/src/ts/lib/generator.js +1 -1
  18. package/src/ts/lib/generator.js.map +1 -1
  19. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +4038 -0
  20. package/src/{cloudscape-website → ts/react-website}/app/files/app/README.md.template +1 -1
  21. package/src/ts/react-website/app/files/app/src/app.tsx.template +17 -0
  22. package/src/{cloudscape-website → ts/react-website}/app/files/app/src/components/AppLayout/index.tsx.template +20 -19
  23. package/src/{cloudscape-website → ts/react-website}/app/files/app/src/main.tsx.template +3 -4
  24. package/src/ts/react-website/app/files/app/src/styles.css.template +2 -0
  25. package/src/{cloudscape-website/app/files/app → ts/react-website/app/files/tanstack-router}/src/routes/__root.tsx.template +6 -1
  26. package/src/{cloudscape-website/app/files/app/src/routes/welcome → ts/react-website/app/files/tanstack-router/src/routes}/index.tsx.template +2 -2
  27. package/src/ts/react-website/app/generator.d.ts +10 -0
  28. package/src/{cloudscape-website → ts/react-website}/app/generator.js +69 -40
  29. package/src/ts/react-website/app/generator.js.map +1 -0
  30. package/src/{cloudscape-website → ts/react-website}/app/schema.d.ts +3 -1
  31. package/src/{cloudscape-website → ts/react-website}/app/schema.json +17 -3
  32. package/src/{cloudscape-website → ts/react-website}/cognito-auth/__snapshots__/generator.spec.ts.snap +1 -3
  33. package/src/ts/react-website/cognito-auth/generator.d.ts +10 -0
  34. package/src/{cloudscape-website → ts/react-website}/cognito-auth/generator.js +11 -11
  35. package/src/ts/react-website/cognito-auth/generator.js.map +1 -0
  36. package/src/{cloudscape-website → ts/react-website}/cognito-auth/schema.d.ts +1 -1
  37. package/src/{cloudscape-website → ts/react-website}/cognito-auth/schema.json +5 -5
  38. package/src/{cloudscape-website → ts/react-website}/runtime-config/__snapshots__/generator.spec.ts.snap +1 -2
  39. package/src/{cloudscape-website → ts/react-website}/runtime-config/generator.d.ts +1 -1
  40. package/src/{cloudscape-website → ts/react-website}/runtime-config/generator.js +7 -7
  41. package/src/ts/react-website/runtime-config/generator.js.map +1 -0
  42. package/src/utils/ast/website.js +1 -1
  43. package/src/utils/ast/website.js.map +1 -1
  44. package/src/utils/versions.d.ts +4 -1
  45. package/src/utils/versions.js +2 -0
  46. package/src/utils/versions.js.map +1 -1
  47. package/src/cloudscape-website/app/__snapshots__/generator.spec.ts.snap +0 -590
  48. package/src/cloudscape-website/app/files/app/src/components/AppLayout/navitems.ts.template +0 -8
  49. package/src/cloudscape-website/app/files/app/src/routes/index.tsx.template +0 -5
  50. package/src/cloudscape-website/app/files/app/src/styles.css.template +0 -1
  51. package/src/cloudscape-website/app/generator.d.ts +0 -10
  52. package/src/cloudscape-website/app/generator.js.map +0 -1
  53. package/src/cloudscape-website/cognito-auth/generator.d.ts +0 -10
  54. package/src/cloudscape-website/cognito-auth/generator.js.map +0 -1
  55. package/src/cloudscape-website/runtime-config/generator.js.map +0 -1
  56. /package/src/{cloudscape-website → ts/react-website}/app/files/app/src/config.ts.template +0 -0
  57. /package/src/{cloudscape-website → ts/react-website}/app/files/app/src/hooks/useAppLayout.tsx.template +0 -0
  58. /package/src/{cloudscape-website → ts/react-website}/app/files/common/constructs/src/app/static-websites/__websiteNameKebabCase__.ts.template +0 -0
  59. /package/src/{cloudscape-website → ts/react-website}/app/files/common/constructs/src/core/static-website.ts.template +0 -0
  60. /package/src/{cloudscape-website → ts/react-website}/app/files/e2e/cypress/src/e2e/app.cy.ts.template +0 -0
  61. /package/src/{cloudscape-website → ts/react-website}/app/files/e2e/cypress/src/support/app.po.ts.template +0 -0
  62. /package/src/{cloudscape-website → ts/react-website}/app/files/e2e/playwright/src/example.spec.ts.template +0 -0
  63. /package/src/{cloudscape-website/app/files/app → ts/react-website/app/files/tanstack-router}/src/routeTree.gen.ts.template +0 -0
  64. /package/src/{cloudscape-website → ts/react-website}/cognito-auth/files/app/components/CognitoAuth/index.tsx.template +0 -0
  65. /package/src/{cloudscape-website → ts/react-website}/cognito-auth/files/common/constructs/src/core/user-identity.ts.template +0 -0
  66. /package/src/{cloudscape-website → ts/react-website}/runtime-config/files/app/components/RuntimeConfig/index.tsx.template +0 -0
  67. /package/src/{cloudscape-website → ts/react-website}/runtime-config/files/app/hooks/useRuntimeConfig.tsx.template +0 -0
  68. /package/src/{cloudscape-website → ts/react-website}/runtime-config/schema.d.ts +0 -0
  69. /package/src/{cloudscape-website → ts/react-website}/runtime-config/schema.json +0 -0
@@ -0,0 +1,4038 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`react-website generator > TailwindCSS integration > should configure vite with TailwindCSS plugin by default > vite.config.ts-with-tailwind 1`] = `
4
+ "import tailwindcss from '@tailwindcss/vite';
5
+ import tsconfigPaths from 'vite-tsconfig-paths';
6
+ import { resolve } from 'path';
7
+ import { tanstackRouter } from '@tanstack/router-plugin/vite';
8
+ /// <reference types='vitest' />
9
+ import { defineConfig } from 'vite';
10
+ import react from '@vitejs/plugin-react';
11
+
12
+ export default defineConfig(() => ({
13
+ define: {
14
+ global: {},
15
+ },
16
+ root: __dirname,
17
+ cacheDir: '../node_modules/.vite/test-app',
18
+ server: {
19
+ port: 4200,
20
+ host: 'localhost',
21
+ },
22
+ preview: {
23
+ port: 4300,
24
+ host: 'localhost',
25
+ },
26
+ plugins: [
27
+ tanstackRouter({
28
+ routesDirectory: resolve(__dirname, 'src/routes'),
29
+ generatedRouteTree: resolve(__dirname, 'src/routeTree.gen.ts'),
30
+ }),
31
+ react(),
32
+ tailwindcss(),
33
+ tsconfigPaths(),
34
+ ],
35
+ build: {
36
+ outDir: '../dist/test-app',
37
+ emptyOutDir: true,
38
+ reportCompressedSize: true,
39
+ commonjsOptions: {
40
+ transformMixedEsModules: true,
41
+ },
42
+ },
43
+ test: {
44
+ watch: false,
45
+ globals: true,
46
+ environment: 'jsdom',
47
+ include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
48
+ reporters: ['default'],
49
+ coverage: {
50
+ reportsDirectory: './test-output/vitest/coverage',
51
+ provider: 'v8' as const,
52
+ },
53
+ passWithNoTests: true,
54
+ },
55
+ }));
56
+ "
57
+ `;
58
+
59
+ exports[`react-website generator > TailwindCSS integration > should configure vite without TailwindCSS plugin when disabled > vite.config.ts-without-tailwind 1`] = `
60
+ "import tsconfigPaths from 'vite-tsconfig-paths';
61
+ import { resolve } from 'path';
62
+ import { tanstackRouter } from '@tanstack/router-plugin/vite';
63
+ /// <reference types='vitest' />
64
+ import { defineConfig } from 'vite';
65
+ import react from '@vitejs/plugin-react';
66
+
67
+ export default defineConfig(() => ({
68
+ define: {
69
+ global: {},
70
+ },
71
+ root: __dirname,
72
+ cacheDir: '../node_modules/.vite/test-app',
73
+ server: {
74
+ port: 4200,
75
+ host: 'localhost',
76
+ },
77
+ preview: {
78
+ port: 4300,
79
+ host: 'localhost',
80
+ },
81
+ plugins: [
82
+ tanstackRouter({
83
+ routesDirectory: resolve(__dirname, 'src/routes'),
84
+ generatedRouteTree: resolve(__dirname, 'src/routeTree.gen.ts'),
85
+ }),
86
+ react(),
87
+ tsconfigPaths(),
88
+ ],
89
+ build: {
90
+ outDir: '../dist/test-app',
91
+ emptyOutDir: true,
92
+ reportCompressedSize: true,
93
+ commonjsOptions: {
94
+ transformMixedEsModules: true,
95
+ },
96
+ },
97
+ test: {
98
+ watch: false,
99
+ globals: true,
100
+ environment: 'jsdom',
101
+ include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
102
+ reporters: ['default'],
103
+ coverage: {
104
+ reportsDirectory: './test-output/vitest/coverage',
105
+ provider: 'v8' as const,
106
+ },
107
+ passWithNoTests: true,
108
+ },
109
+ }));
110
+ "
111
+ `;
112
+
113
+ exports[`react-website generator > TailwindCSS integration > should include TailwindCSS import in styles.css by default > styles.css-with-tailwind 1`] = `
114
+ "@import 'tailwindcss';
115
+ /* You can add global styles to this file, and also import other style files */
116
+ "
117
+ `;
118
+
119
+ exports[`react-website generator > TailwindCSS integration > should not include TailwindCSS import in styles.css when disabled > styles.css-without-tailwind 1`] = `
120
+ "/* You can add global styles to this file, and also import other style files */
121
+ "
122
+ `;
123
+
124
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > .gitignore 1`] = `
125
+ "vite.config.*.timestamp*
126
+ vitest.config.*.timestamp*
127
+
128
+ runtime-config.json"
129
+ `;
130
+
131
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > .prettierrc 1`] = `
132
+ "{ "singleQuote": true }
133
+ "
134
+ `;
135
+
136
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > eslint.config.mjs 1`] = `
137
+ "import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
138
+ import nx from '@nx/eslint-plugin';
139
+
140
+ export default [
141
+ eslintPluginPrettierRecommended,
142
+ ...nx.configs['flat/base'],
143
+ ...nx.configs['flat/typescript'],
144
+ ...nx.configs['flat/javascript'],
145
+ {
146
+ ignores: [
147
+ '**/dist',
148
+ '**/vite.config.*.timestamp*',
149
+ '**/vitest.config.*.timestamp*',
150
+ '**/vite.config.ts.timestamp*',
151
+ ],
152
+ },
153
+ {
154
+ files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
155
+ rules: {
156
+ '@nx/enforce-module-boundaries': [
157
+ 'error',
158
+ {
159
+ enforceBuildableLibDependency: true,
160
+ allow: ['^.*/eslint(\\\\.base)?\\\\.config\\\\.[cm]?js$'],
161
+ depConstraints: [
162
+ {
163
+ sourceTag: '*',
164
+ onlyDependOnLibsWithTags: ['*'],
165
+ },
166
+ ],
167
+ },
168
+ ],
169
+ },
170
+ },
171
+ {
172
+ files: [
173
+ '**/*.ts',
174
+ '**/*.tsx',
175
+ '**/*.cts',
176
+ '**/*.mts',
177
+ '**/*.js',
178
+ '**/*.jsx',
179
+ '**/*.cjs',
180
+ '**/*.mjs',
181
+ ],
182
+ rules: {},
183
+ },
184
+ ];
185
+ "
186
+ `;
187
+
188
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > nx.json 1`] = `
189
+ "{
190
+ "affected": {
191
+ "defaultBase": "main"
192
+ },
193
+ "targetDefaults": {
194
+ "build": {
195
+ "cache": true,
196
+ "dependsOn": ["^build"],
197
+ "inputs": ["default"]
198
+ },
199
+ "lint": {
200
+ "cache": true,
201
+ "configurations": {
202
+ "fix": {
203
+ "fix": true
204
+ }
205
+ },
206
+ "inputs": [
207
+ "default",
208
+ "{workspaceRoot}/eslint.config.mjs",
209
+ "{projectRoot}/eslint.config.mjs"
210
+ ]
211
+ },
212
+ "@nx/eslint:lint": {
213
+ "cache": true,
214
+ "inputs": [
215
+ "default",
216
+ "{workspaceRoot}/.eslintrc.json",
217
+ "{workspaceRoot}/.eslintignore",
218
+ "{workspaceRoot}/eslint.config.mjs"
219
+ ]
220
+ },
221
+ "@nx/vite:test": {
222
+ "cache": true,
223
+ "inputs": ["default", "^default"],
224
+ "configurations": {
225
+ "update-snapshot": {
226
+ "args": "--update"
227
+ }
228
+ }
229
+ },
230
+ "@nx/vite:build": {
231
+ "cache": true,
232
+ "dependsOn": ["^build"],
233
+ "inputs": ["default", "^default"]
234
+ },
235
+ "test": {
236
+ "dependsOn": ["^build"],
237
+ "inputs": ["default"]
238
+ },
239
+ "compile": {
240
+ "cache": true,
241
+ "inputs": ["default"]
242
+ }
243
+ },
244
+ "generators": {
245
+ "@nx/react": {
246
+ "application": {
247
+ "babel": true,
248
+ "style": "css",
249
+ "linter": "eslint",
250
+ "bundler": "vite"
251
+ },
252
+ "component": {
253
+ "style": "css"
254
+ },
255
+ "library": {
256
+ "style": "css",
257
+ "linter": "eslint"
258
+ }
259
+ }
260
+ },
261
+ "plugins": [
262
+ {
263
+ "plugin": "@nx/js/typescript",
264
+ "options": {
265
+ "typecheck": {
266
+ "targetName": "typecheck"
267
+ },
268
+ "build": {
269
+ "targetName": "compile",
270
+ "configName": "tsconfig.lib.json",
271
+ "buildDepsName": "build-deps",
272
+ "watchDepsName": "watch-deps"
273
+ }
274
+ }
275
+ },
276
+ {
277
+ "plugin": "@nx/eslint/plugin",
278
+ "options": {
279
+ "targetName": "lint"
280
+ }
281
+ }
282
+ ],
283
+ "namedInputs": {
284
+ "default": [
285
+ {
286
+ "dependentTasksOutputFiles": "**/*",
287
+ "transitive": true
288
+ }
289
+ ]
290
+ }
291
+ }
292
+ "
293
+ `;
294
+
295
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > package.json 1`] = `
296
+ "{
297
+ "name": "@proj/source",
298
+ "dependencies": {
299
+ "@cloudscape-design/board-components": "^3.0.94",
300
+ "@cloudscape-design/components": "^3.0.928",
301
+ "@cloudscape-design/global-styles": "^1.0.38",
302
+ "aws-cdk-lib": "^2.200.0",
303
+ "constructs": "^10.4.2",
304
+ "react": "19.0.0",
305
+ "react-dom": "19.0.0",
306
+ "tailwindcss": "^4.1.11"
307
+ },
308
+ "devDependencies": {
309
+ "@eslint/js": "^9.8.0",
310
+ "@nx/eslint": "21.0.3",
311
+ "@nx/eslint-plugin": "21.0.3",
312
+ "@nx/js": "21.0.3",
313
+ "@nx/react": "21.0.3",
314
+ "@nx/vite": "21.0.3",
315
+ "@nx/web": "21.0.3",
316
+ "@swc-node/register": "~1.9.1",
317
+ "@swc/cli": "~0.6.0",
318
+ "@swc/core": "~1.5.7",
319
+ "@swc/helpers": "~0.5.11",
320
+ "@tailwindcss/vite": "^4.1.11",
321
+ "@testing-library/dom": "10.4.0",
322
+ "@testing-library/react": "16.1.0",
323
+ "@types/node": "^22.13.13",
324
+ "@types/react": "19.0.0",
325
+ "@types/react-dom": "19.0.0",
326
+ "@vitejs/plugin-react": "^4.2.0",
327
+ "@vitest/coverage-v8": "^3.0.5",
328
+ "@vitest/ui": "^3.0.0",
329
+ "eslint": "^9.8.0",
330
+ "eslint-config-prettier": "^10.0.0",
331
+ "eslint-plugin-import": "2.31.0",
332
+ "eslint-plugin-jsx-a11y": "6.10.1",
333
+ "eslint-plugin-prettier": "^5.2.5",
334
+ "eslint-plugin-react": "7.35.0",
335
+ "eslint-plugin-react-hooks": "5.0.0",
336
+ "jiti": "2.4.2",
337
+ "jsdom": "~22.1.0",
338
+ "jsonc-eslint-parser": "^2.4.0",
339
+ "prettier": "^3.5.3",
340
+ "typescript": "~5.7.2",
341
+ "typescript-eslint": "^8.19.0",
342
+ "vite": "^6.0.0",
343
+ "vite-tsconfig-paths": "^5.1.4",
344
+ "vitest": "^3.0.0"
345
+ },
346
+ "type": "module"
347
+ }
348
+ "
349
+ `;
350
+
351
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/constructs/README.md 1`] = `
352
+ "# @proj/common-constructs
353
+
354
+ This library was generated with [@aws/nx-plugin](https://github.com/awslabs/nx-plugin-for-aws/).
355
+
356
+ ## Building
357
+
358
+ Run \`npx nx build @proj/common-constructs [--skip-nx-cache]\` to build the application.
359
+
360
+ ## Running unit tests
361
+
362
+ Run \`npx nx test @proj/common-constructs\` to execute the unit tests via Vitest.
363
+
364
+ ### Updating snapshots
365
+
366
+ To update snapshots, run the following command:
367
+
368
+ \`npx nx test @proj/common-constructs --configuration=update-snapshot\`
369
+
370
+ ## Run lint
371
+
372
+ Run \`npx nx lint @proj/common-constructs\`
373
+
374
+ ### Fixable issues
375
+
376
+ You can also automatiaclly fix some lint errors by running the following command:
377
+
378
+ \`npx nx lint @proj/common-constructs --configuration=fix\`
379
+
380
+ ## Useful links
381
+
382
+ - [common-constructs reference docs](TODO)
383
+ - [Learn more about NX](https://nx.dev/getting-started/intro)
384
+ "
385
+ `;
386
+
387
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/constructs/eslint.config.mjs 1`] = `
388
+ "import baseConfig from '../../../eslint.config.mjs';
389
+
390
+ export default [
391
+ ...baseConfig,
392
+ {
393
+ files: ['**/*.json'],
394
+ rules: {
395
+ '@nx/dependency-checks': [
396
+ 'warn',
397
+ {
398
+ ignoredFiles: [
399
+ '{projectRoot}/eslint.config.{js,cjs,mjs}',
400
+ '{projectRoot}/vite.config.{js,ts,mjs,mts}',
401
+ ],
402
+ },
403
+ ],
404
+ },
405
+ languageOptions: {
406
+ parser: await import('jsonc-eslint-parser'),
407
+ },
408
+ },
409
+ ];
410
+ "
411
+ `;
412
+
413
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/constructs/project.json 1`] = `
414
+ "{
415
+ "name": "@proj/common-constructs",
416
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
417
+ "sourceRoot": "packages/common/constructs/src",
418
+ "projectType": "library",
419
+ "tags": [],
420
+ "targets": {
421
+ "build": {
422
+ "dependsOn": ["lint", "compile", "test", "@proj/test-app:build"]
423
+ },
424
+ "compile": {
425
+ "executor": "nx:run-commands",
426
+ "outputs": ["{workspaceRoot}/dist/packages/common/constructs/tsc"],
427
+ "options": {
428
+ "command": "tsc --build tsconfig.lib.json",
429
+ "cwd": "{projectRoot}"
430
+ }
431
+ },
432
+ "test": {
433
+ "executor": "@nx/vite:test",
434
+ "outputs": ["{options.reportsDirectory}"],
435
+ "options": {
436
+ "reportsDirectory": "../../../coverage/packages/common/constructs"
437
+ }
438
+ }
439
+ },
440
+ "metadata": {
441
+ "generator": "ts#project"
442
+ }
443
+ }
444
+ "
445
+ `;
446
+
447
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/constructs/src/app/index.ts 1`] = `
448
+ "export * from './static-websites/index.js';
449
+ "
450
+ `;
451
+
452
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/constructs/src/app/static-websites/index.ts 1`] = `
453
+ "export * from './test-app.js';
454
+ "
455
+ `;
456
+
457
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/constructs/src/app/static-websites/test-app.ts 1`] = `
458
+ "import * as url from 'url';
459
+ import { Construct } from 'constructs';
460
+ import { StaticWebsite } from '../../core/index.js';
461
+
462
+ export class TestApp extends StaticWebsite {
463
+ constructor(scope: Construct, id: string) {
464
+ super(scope, id, {
465
+ websiteFilePath: url.fileURLToPath(
466
+ new URL('../../../../../../dist/test-app/bundle', import.meta.url),
467
+ ),
468
+ });
469
+ }
470
+ }
471
+ "
472
+ `;
473
+
474
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/constructs/src/core/app.ts 1`] = `
475
+ "import { App as _App, AppProps, Aspects, IAspect, Stack } from 'aws-cdk-lib';
476
+ import { IConstruct } from 'constructs';
477
+
478
+ export class App extends _App {
479
+ constructor(props?: AppProps) {
480
+ super(props);
481
+
482
+ Aspects.of(this).add(new MetricsAspect());
483
+ }
484
+ }
485
+
486
+ /**
487
+ * Adds information to CloudFormation stack descriptions to provide usage metrics for @aws/nx-plugin
488
+ */
489
+ class MetricsAspect implements IAspect {
490
+ visit(node: IConstruct): void {
491
+ if (node instanceof Stack) {
492
+ const id = 'uksb-4wk0bqpg5s';
493
+ const version = '0.0.0';
494
+ const tags: string[] = ['g5'];
495
+ node.templateOptions.description =
496
+ \`\${node.templateOptions.description ?? ''} (\${id}) (version:\${version}) (tag:\${tags.join(',')})\`.trim();
497
+ }
498
+ }
499
+ }
500
+ "
501
+ `;
502
+
503
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/constructs/src/core/index.ts 1`] = `
504
+ "export * from './static-website.js';
505
+ export * from './app.js';
506
+ export * from './runtime-config.js';
507
+ "
508
+ `;
509
+
510
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/constructs/src/core/runtime-config.ts 1`] = `
511
+ "import type { IRuntimeConfig } from ':proj/common-types';
512
+ import { Stack } from 'aws-cdk-lib';
513
+ import { Construct } from 'constructs';
514
+
515
+ const RuntimeConfigKey = '__RuntimeConfig__';
516
+
517
+ export class RuntimeConfig extends Construct {
518
+ private readonly _runtimeConfig: Partial<IRuntimeConfig> = {};
519
+
520
+ static ensure(scope: Construct): RuntimeConfig {
521
+ const stack = Stack.of(scope);
522
+ return (
523
+ RuntimeConfig.of(scope) ?? new RuntimeConfig(stack, RuntimeConfigKey)
524
+ );
525
+ }
526
+
527
+ static of(scope: Construct): RuntimeConfig | undefined {
528
+ const stack = Stack.of(scope);
529
+ return stack.node.tryFindChild(RuntimeConfigKey) as
530
+ | RuntimeConfig
531
+ | undefined;
532
+ }
533
+
534
+ constructor(scope: Construct, id: string) {
535
+ super(scope, id);
536
+ }
537
+
538
+ get config(): Partial<IRuntimeConfig> {
539
+ return this._runtimeConfig;
540
+ }
541
+ }
542
+ "
543
+ `;
544
+
545
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/constructs/src/core/static-website.ts 1`] = `
546
+ "import { CfnJson, CfnOutput, RemovalPolicy, Stack, Token } from 'aws-cdk-lib';
547
+ import { Distribution, ViewerProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
548
+ import { S3BucketOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
549
+ import {
550
+ BlockPublicAccess,
551
+ Bucket,
552
+ BucketEncryption,
553
+ IBucket,
554
+ ObjectOwnership,
555
+ } from 'aws-cdk-lib/aws-s3';
556
+ import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';
557
+ import { Construct } from 'constructs';
558
+ import { RuntimeConfig } from './runtime-config.js';
559
+ import { Key } from 'aws-cdk-lib/aws-kms';
560
+ import { CfnWebACL } from 'aws-cdk-lib/aws-wafv2';
561
+ const DEFAULT_RUNTIME_CONFIG_FILENAME = 'runtime-config.json';
562
+
563
+ export interface StaticWebsiteProps {
564
+ readonly websiteFilePath: string;
565
+ }
566
+
567
+ /**
568
+ * Deploys a Static Website using by default a private S3 bucket as an origin and Cloudfront as the entrypoint.
569
+ *
570
+ * This construct configures a webAcl containing rules that are generally applicable to web applications. This
571
+ * provides protection against exploitation of a wide range of vulnerabilities, including some of the high risk
572
+ * and commonly occurring vulnerabilities described in OWASP publications such as OWASP Top 10.
573
+ *
574
+ */
575
+ export class StaticWebsite extends Construct {
576
+ public readonly websiteBucket: IBucket;
577
+ public readonly cloudFrontDistribution: Distribution;
578
+ public readonly bucketDeployment: BucketDeployment;
579
+
580
+ constructor(
581
+ scope: Construct,
582
+ id: string,
583
+ { websiteFilePath }: StaticWebsiteProps,
584
+ ) {
585
+ super(scope, id);
586
+ this.node.setContext(
587
+ '@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy',
588
+ true,
589
+ );
590
+
591
+ const websiteKey = new Key(this, 'WebsiteKey', {
592
+ enableKeyRotation: true,
593
+ });
594
+
595
+ const accessLogsBucket = new Bucket(this, 'AccessLogsBucket', {
596
+ versioned: false,
597
+ enforceSSL: true,
598
+ autoDeleteObjects: true,
599
+ removalPolicy: RemovalPolicy.DESTROY,
600
+ encryption: BucketEncryption.KMS,
601
+ encryptionKey: websiteKey,
602
+ objectOwnership: ObjectOwnership.OBJECT_WRITER,
603
+ publicReadAccess: false,
604
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
605
+ });
606
+ // S3 Bucket to hold website files
607
+ this.websiteBucket = new Bucket(this, 'WebsiteBucket', {
608
+ versioned: true,
609
+ enforceSSL: true,
610
+ autoDeleteObjects: true,
611
+ removalPolicy: RemovalPolicy.DESTROY,
612
+ encryption: BucketEncryption.KMS,
613
+ encryptionKey: websiteKey,
614
+ objectOwnership: ObjectOwnership.BUCKET_OWNER_ENFORCED,
615
+ publicReadAccess: false,
616
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
617
+ serverAccessLogsPrefix: 'website-access-logs',
618
+ serverAccessLogsBucket: accessLogsBucket,
619
+ });
620
+ // Web ACL
621
+ const wafStack = new CloudfrontWebAcl(this, 'waf');
622
+
623
+ // Cloudfront Distribution
624
+ const logBucket = new Bucket(this, 'DistributionLogBucket', {
625
+ enforceSSL: true,
626
+ autoDeleteObjects: true,
627
+ removalPolicy: RemovalPolicy.DESTROY,
628
+ encryption: BucketEncryption.KMS,
629
+ encryptionKey: websiteKey,
630
+ objectOwnership: ObjectOwnership.BUCKET_OWNER_PREFERRED,
631
+ publicReadAccess: false,
632
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
633
+ serverAccessLogsPrefix: 'distribution-access-logs',
634
+ serverAccessLogsBucket: accessLogsBucket,
635
+ });
636
+ const defaultRootObject = 'index.html';
637
+ this.cloudFrontDistribution = new Distribution(
638
+ this,
639
+ 'CloudfrontDistribution',
640
+ {
641
+ webAclId: wafStack.wafArn,
642
+ enableLogging: true,
643
+ logBucket: logBucket,
644
+ defaultBehavior: {
645
+ origin: S3BucketOrigin.withOriginAccessControl(this.websiteBucket),
646
+ viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
647
+ },
648
+ defaultRootObject,
649
+ errorResponses: [
650
+ {
651
+ httpStatus: 404, // We need to redirect "key not found errors" to index.html for single page apps
652
+ responseHttpStatus: 200,
653
+ responsePagePath: \`/\${defaultRootObject}\`,
654
+ },
655
+ {
656
+ httpStatus: 403, // We need to redirect reloads from paths (e.g. /foo/bar) to index.html for single page apps
657
+ responseHttpStatus: 200,
658
+ responsePagePath: \`/\${defaultRootObject}\`,
659
+ },
660
+ ],
661
+ },
662
+ );
663
+ // Deploy Website
664
+ this.bucketDeployment = new BucketDeployment(this, 'WebsiteDeployment', {
665
+ sources: [
666
+ Source.asset(websiteFilePath),
667
+ Source.jsonData(
668
+ DEFAULT_RUNTIME_CONFIG_FILENAME,
669
+ this.resolveTokens(RuntimeConfig.ensure(this).config),
670
+ ),
671
+ ],
672
+ destinationBucket: this.websiteBucket,
673
+ // Files in the distribution's edge caches will be invalidated after files are uploaded to the destination bucket.
674
+ distribution: this.cloudFrontDistribution,
675
+ memoryLimit: 1024,
676
+ });
677
+ new CfnOutput(this, 'DistributionDomainName', {
678
+ value: this.cloudFrontDistribution.domainName,
679
+ });
680
+ new CfnOutput(this, 'WebsiteBucketName', {
681
+ value: this.websiteBucket.bucketName,
682
+ });
683
+ }
684
+ private resolveTokens = (payload: any) => {
685
+ const _payload: Record<string, any> = {};
686
+ Object.entries(payload).forEach(([key, value]) => {
687
+ if (
688
+ Token.isUnresolved(value) ||
689
+ (typeof value === 'string' && value.endsWith('}}'))
690
+ ) {
691
+ _payload[key] = new CfnJson(this, \`ResolveToken-\${key}\`, {
692
+ value,
693
+ }).value;
694
+ } else if (typeof value === 'object') {
695
+ _payload[key] = this.resolveTokens(value);
696
+ } else if (Array.isArray(value)) {
697
+ _payload[key] = value.map((v) => this.resolveTokens(v));
698
+ } else {
699
+ _payload[key] = value;
700
+ }
701
+ });
702
+ return _payload;
703
+ };
704
+ }
705
+
706
+ export class CloudfrontWebAcl extends Stack {
707
+ public readonly wafArn;
708
+ constructor(scope: Construct, id: string) {
709
+ super(scope, id, {
710
+ env: {
711
+ region: 'us-east-1',
712
+ account: Stack.of(scope).account,
713
+ },
714
+ crossRegionReferences: true,
715
+ });
716
+
717
+ this.wafArn = new CfnWebACL(this, 'WebAcl', {
718
+ defaultAction: { allow: {} },
719
+ scope: 'CLOUDFRONT',
720
+ visibilityConfig: {
721
+ cloudWatchMetricsEnabled: true,
722
+ metricName: id,
723
+ sampledRequestsEnabled: true,
724
+ },
725
+ rules: [
726
+ {
727
+ name: 'CRSRule',
728
+ priority: 0,
729
+ statement: {
730
+ managedRuleGroupStatement: {
731
+ name: 'AWSManagedRulesCommonRuleSet',
732
+ vendorName: 'AWS',
733
+ },
734
+ },
735
+ visibilityConfig: {
736
+ cloudWatchMetricsEnabled: true,
737
+ metricName: 'MetricForWebACLCDK-CRS',
738
+ sampledRequestsEnabled: true,
739
+ },
740
+ overrideAction: {
741
+ none: {},
742
+ },
743
+ },
744
+ ],
745
+ }).attrArn;
746
+ }
747
+ }
748
+ "
749
+ `;
750
+
751
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/constructs/src/index.ts 1`] = `
752
+ "export * from './app/index.js';
753
+ export * from './core/index.js';
754
+ "
755
+ `;
756
+
757
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/constructs/tsconfig.json 1`] = `
758
+ "{
759
+ "extends": "../../../tsconfig.base.json",
760
+ "files": [],
761
+ "include": [],
762
+ "references": [
763
+ {
764
+ "path": "./tsconfig.lib.json"
765
+ },
766
+ {
767
+ "path": "./tsconfig.spec.json"
768
+ }
769
+ ],
770
+ "compilerOptions": {}
771
+ }
772
+ "
773
+ `;
774
+
775
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/constructs/tsconfig.lib.json 1`] = `
776
+ "{
777
+ "extends": "../../../tsconfig.base.json",
778
+ "compilerOptions": {
779
+ "rootDir": ".",
780
+ "outDir": "../../../dist/packages/common/constructs/tsc",
781
+ "tsBuildInfoFile": "../../../dist/packages/common/constructs/tsc/tsconfig.lib.tsbuildinfo",
782
+ "emitDeclarationOnly": false,
783
+ "module": "nodenext",
784
+ "moduleResolution": "nodenext",
785
+ "types": ["node"]
786
+ },
787
+ "include": ["src/**/*.ts"],
788
+ "references": [],
789
+ "exclude": [
790
+ "vite.config.ts",
791
+ "vite.config.mts",
792
+ "vitest.config.ts",
793
+ "vitest.config.mts",
794
+ "src/**/*.test.ts",
795
+ "src/**/*.spec.ts",
796
+ "src/**/*.test.tsx",
797
+ "src/**/*.spec.tsx",
798
+ "src/**/*.test.js",
799
+ "src/**/*.spec.js",
800
+ "src/**/*.test.jsx",
801
+ "src/**/*.spec.jsx"
802
+ ]
803
+ }
804
+ "
805
+ `;
806
+
807
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/constructs/tsconfig.spec.json 1`] = `
808
+ "{
809
+ "extends": "../../../tsconfig.base.json",
810
+ "compilerOptions": {
811
+ "outDir": "./out-tsc/vitest",
812
+ "types": [
813
+ "vitest/globals",
814
+ "vitest/importMeta",
815
+ "vite/client",
816
+ "node",
817
+ "vitest"
818
+ ],
819
+ "module": "nodenext",
820
+ "moduleResolution": "nodenext"
821
+ },
822
+ "include": [
823
+ "vite.config.ts",
824
+ "vite.config.mts",
825
+ "vitest.config.ts",
826
+ "vitest.config.mts",
827
+ "src/**/*.test.ts",
828
+ "src/**/*.spec.ts",
829
+ "src/**/*.test.tsx",
830
+ "src/**/*.spec.tsx",
831
+ "src/**/*.test.js",
832
+ "src/**/*.spec.js",
833
+ "src/**/*.test.jsx",
834
+ "src/**/*.spec.jsx",
835
+ "src/**/*.d.ts"
836
+ ],
837
+ "references": [
838
+ {
839
+ "path": "./tsconfig.lib.json"
840
+ }
841
+ ]
842
+ }
843
+ "
844
+ `;
845
+
846
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/constructs/vite.config.ts 1`] = `
847
+ "import { defineConfig } from 'vite';
848
+
849
+ export default defineConfig(() => ({
850
+ root: __dirname,
851
+ cacheDir: '../../../node_modules/.vite/packages/common/constructs',
852
+ plugins: [],
853
+ // Uncomment this if you are using workers.
854
+ // worker: {
855
+ // plugins: [ nxViteTsPaths() ],
856
+ // },
857
+ test: {
858
+ watch: false,
859
+ globals: true,
860
+ environment: 'jsdom',
861
+ include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
862
+ reporters: ['default'],
863
+ coverage: {
864
+ reportsDirectory: './test-output/vitest/coverage',
865
+ provider: 'v8' as const,
866
+ },
867
+ passWithNoTests: true,
868
+ },
869
+ }));
870
+ "
871
+ `;
872
+
873
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/types/README.md 1`] = `
874
+ "# @proj/common-types
875
+
876
+ This library was generated with [@aws/nx-plugin](https://github.com/awslabs/nx-plugin-for-aws/).
877
+
878
+ ## Building
879
+
880
+ Run \`npx nx build @proj/common-types [--skip-nx-cache]\` to build the application.
881
+
882
+ ## Running unit tests
883
+
884
+ Run \`npx nx test @proj/common-types\` to execute the unit tests via Vitest.
885
+
886
+ ### Updating snapshots
887
+
888
+ To update snapshots, run the following command:
889
+
890
+ \`npx nx test @proj/common-types --configuration=update-snapshot\`
891
+
892
+ ## Run lint
893
+
894
+ Run \`npx nx lint @proj/common-types\`
895
+
896
+ ### Fixable issues
897
+
898
+ You can also automatiaclly fix some lint errors by running the following command:
899
+
900
+ \`npx nx lint @proj/common-types --configuration=fix\`
901
+
902
+ ## Useful links
903
+
904
+ - [common-types reference docs](TODO)
905
+ - [Learn more about NX](https://nx.dev/getting-started/intro)
906
+ "
907
+ `;
908
+
909
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/types/eslint.config.mjs 1`] = `
910
+ "import baseConfig from '../../../eslint.config.mjs';
911
+
912
+ export default [
913
+ ...baseConfig,
914
+ {
915
+ files: ['**/*.json'],
916
+ rules: {
917
+ '@nx/dependency-checks': [
918
+ 'warn',
919
+ {
920
+ ignoredFiles: [
921
+ '{projectRoot}/eslint.config.{js,cjs,mjs}',
922
+ '{projectRoot}/vite.config.{js,ts,mjs,mts}',
923
+ ],
924
+ },
925
+ ],
926
+ },
927
+ languageOptions: {
928
+ parser: await import('jsonc-eslint-parser'),
929
+ },
930
+ },
931
+ ];
932
+ "
933
+ `;
934
+
935
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/types/project.json 1`] = `
936
+ "{
937
+ "name": "@proj/common-types",
938
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
939
+ "sourceRoot": "packages/common/types/src",
940
+ "projectType": "library",
941
+ "tags": [],
942
+ "targets": {
943
+ "build": {
944
+ "dependsOn": ["lint", "compile", "test"]
945
+ },
946
+ "compile": {
947
+ "executor": "nx:run-commands",
948
+ "outputs": ["{workspaceRoot}/dist/packages/common/types/tsc"],
949
+ "options": {
950
+ "command": "tsc --build tsconfig.lib.json",
951
+ "cwd": "{projectRoot}"
952
+ }
953
+ },
954
+ "test": {
955
+ "executor": "@nx/vite:test",
956
+ "outputs": ["{options.reportsDirectory}"],
957
+ "options": {
958
+ "reportsDirectory": "../../../coverage/packages/common/types"
959
+ }
960
+ }
961
+ },
962
+ "metadata": {
963
+ "generator": "ts#project"
964
+ }
965
+ }
966
+ "
967
+ `;
968
+
969
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/types/src/index.ts 1`] = `
970
+ "export * from './runtime-config.js';
971
+ "
972
+ `;
973
+
974
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/types/src/runtime-config.ts 1`] = `
975
+ "// eslint-disable-next-line @typescript-eslint/no-empty-object-type, @typescript-eslint/no-empty-interface
976
+ export interface IRuntimeConfig {}
977
+ "
978
+ `;
979
+
980
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/types/tsconfig.json 1`] = `
981
+ "{
982
+ "extends": "../../../tsconfig.base.json",
983
+ "files": [],
984
+ "include": [],
985
+ "references": [
986
+ {
987
+ "path": "./tsconfig.lib.json"
988
+ },
989
+ {
990
+ "path": "./tsconfig.spec.json"
991
+ }
992
+ ],
993
+ "compilerOptions": {}
994
+ }
995
+ "
996
+ `;
997
+
998
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/types/tsconfig.lib.json 1`] = `
999
+ "{
1000
+ "extends": "../../../tsconfig.base.json",
1001
+ "compilerOptions": {
1002
+ "rootDir": ".",
1003
+ "outDir": "../../../dist/packages/common/types/tsc",
1004
+ "tsBuildInfoFile": "../../../dist/packages/common/types/tsc/tsconfig.lib.tsbuildinfo",
1005
+ "emitDeclarationOnly": false,
1006
+ "module": "nodenext",
1007
+ "moduleResolution": "nodenext",
1008
+ "types": ["node"]
1009
+ },
1010
+ "include": ["src/**/*.ts"],
1011
+ "references": [],
1012
+ "exclude": [
1013
+ "vite.config.ts",
1014
+ "vite.config.mts",
1015
+ "vitest.config.ts",
1016
+ "vitest.config.mts",
1017
+ "src/**/*.test.ts",
1018
+ "src/**/*.spec.ts",
1019
+ "src/**/*.test.tsx",
1020
+ "src/**/*.spec.tsx",
1021
+ "src/**/*.test.js",
1022
+ "src/**/*.spec.js",
1023
+ "src/**/*.test.jsx",
1024
+ "src/**/*.spec.jsx"
1025
+ ]
1026
+ }
1027
+ "
1028
+ `;
1029
+
1030
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/types/tsconfig.spec.json 1`] = `
1031
+ "{
1032
+ "extends": "../../../tsconfig.base.json",
1033
+ "compilerOptions": {
1034
+ "outDir": "./out-tsc/vitest",
1035
+ "types": [
1036
+ "vitest/globals",
1037
+ "vitest/importMeta",
1038
+ "vite/client",
1039
+ "node",
1040
+ "vitest"
1041
+ ],
1042
+ "module": "nodenext",
1043
+ "moduleResolution": "nodenext"
1044
+ },
1045
+ "include": [
1046
+ "vite.config.ts",
1047
+ "vite.config.mts",
1048
+ "vitest.config.ts",
1049
+ "vitest.config.mts",
1050
+ "src/**/*.test.ts",
1051
+ "src/**/*.spec.ts",
1052
+ "src/**/*.test.tsx",
1053
+ "src/**/*.spec.tsx",
1054
+ "src/**/*.test.js",
1055
+ "src/**/*.spec.js",
1056
+ "src/**/*.test.jsx",
1057
+ "src/**/*.spec.jsx",
1058
+ "src/**/*.d.ts"
1059
+ ],
1060
+ "references": [
1061
+ {
1062
+ "path": "./tsconfig.lib.json"
1063
+ }
1064
+ ]
1065
+ }
1066
+ "
1067
+ `;
1068
+
1069
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/types/vite.config.ts 1`] = `
1070
+ "import { defineConfig } from 'vite';
1071
+
1072
+ export default defineConfig(() => ({
1073
+ root: __dirname,
1074
+ cacheDir: '../../../node_modules/.vite/packages/common/types',
1075
+ plugins: [],
1076
+ // Uncomment this if you are using workers.
1077
+ // worker: {
1078
+ // plugins: [ nxViteTsPaths() ],
1079
+ // },
1080
+ test: {
1081
+ watch: false,
1082
+ globals: true,
1083
+ environment: 'jsdom',
1084
+ include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
1085
+ reporters: ['default'],
1086
+ coverage: {
1087
+ reportsDirectory: './test-output/vitest/coverage',
1088
+ provider: 'v8' as const,
1089
+ },
1090
+ passWithNoTests: true,
1091
+ },
1092
+ }));
1093
+ "
1094
+ `;
1095
+
1096
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > pnpm-workspace.yaml 1`] = `
1097
+ "packages:
1098
+ - 'packages/*'
1099
+ - 'test-app'
1100
+ - 'packages/common/*'
1101
+ - 'packages/common/constructs'
1102
+ "
1103
+ `;
1104
+
1105
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/README.md 1`] = `
1106
+ "# @proj/test-app
1107
+
1108
+ This library was generated with [@aws/nx-plugin](https://github.com/awslabs/nx-plugin-for-aws/).
1109
+
1110
+ ## Building
1111
+
1112
+ Run \`npx nx build @proj/test-app [--skip-nx-cache]\` to build the application.
1113
+
1114
+ ## Run dev server
1115
+
1116
+ Run \`npx nx serve @proj/test-app\`
1117
+
1118
+ ## Running unit tests
1119
+
1120
+ Run \`npx nx test @proj/test-app\` to execute the unit tests via Vitest.
1121
+
1122
+ ### Updating snapshots
1123
+
1124
+ To update snapshots, run the following command:
1125
+
1126
+ \`npx nx test @proj/test-app --configuration=update-snapshot\`
1127
+
1128
+ ## Run lint
1129
+
1130
+ Run \`npx nx lint @proj/test-app\`
1131
+
1132
+ ### Fixable issues
1133
+
1134
+ You can also automatically fix some lint errors by running the following command:
1135
+
1136
+ \`npx nx lint @proj/test-app --configuration=fix\`
1137
+
1138
+ ### Runtime config
1139
+
1140
+ In order to integrate with cognito or trpc backends, you need to have a \`runtime-config.json\` file in your \`/public\` website directory. You can fetch this is follows:
1141
+
1142
+ \`npx nx run @proj/test-app:load:runtime-config\`
1143
+
1144
+ > [!IMPORTANT]
1145
+ > Ensure you have AWS CLI and curl installed
1146
+ > You have deployed your CDK infrastructure into the appropriate account
1147
+ > You have assumed a role in the AWS account with sufficient permissions to call describe-stacks from cloudformation
1148
+
1149
+ ## Useful links
1150
+
1151
+ - [React website reference docs](TODO)
1152
+ - [Learn more about NX](https://nx.dev/getting-started/intro)
1153
+ "
1154
+ `;
1155
+
1156
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/eslint.config.mjs 1`] = `
1157
+ "import nx from '@nx/eslint-plugin';
1158
+ import baseConfig from '../eslint.config.mjs';
1159
+
1160
+ export default [
1161
+ ...baseConfig,
1162
+ ...nx.configs['flat/react'],
1163
+ {
1164
+ files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
1165
+ // Override or add rules here
1166
+ rules: {},
1167
+ },
1168
+ ];
1169
+ "
1170
+ `;
1171
+
1172
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/index.html 1`] = `
1173
+ "<!doctype html>
1174
+ <html lang="en">
1175
+ <head>
1176
+ <meta charset="utf-8" />
1177
+ <title>TestApp</title>
1178
+ <base href="/" />
1179
+
1180
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
1181
+ <link rel="icon" type="image/x-icon" href="/favicon.ico" />
1182
+ <link rel="stylesheet" href="/src/styles.css" />
1183
+ </head>
1184
+ <body>
1185
+ <div id="root"></div>
1186
+ <script type="module" src="/src/main.tsx"></script>
1187
+ </body>
1188
+ </html>
1189
+ "
1190
+ `;
1191
+
1192
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/project.json 1`] = `
1193
+ "{
1194
+ "name": "@proj/test-app",
1195
+ "$schema": "../node_modules/nx/schemas/project-schema.json",
1196
+ "sourceRoot": "test-app/src",
1197
+ "projectType": "application",
1198
+ "tags": [],
1199
+ "targets": {
1200
+ "build": {
1201
+ "dependsOn": ["lint", "compile", "bundle", "test"],
1202
+ "options": {
1203
+ "outputPath": "dist/test-app/bundle"
1204
+ }
1205
+ },
1206
+ "bundle": {
1207
+ "executor": "@nx/vite:build",
1208
+ "outputs": ["{options.outputPath}"],
1209
+ "defaultConfiguration": "production",
1210
+ "options": {
1211
+ "outputPath": "dist/test-app/bundle"
1212
+ },
1213
+ "configurations": {
1214
+ "development": {
1215
+ "mode": "development"
1216
+ },
1217
+ "production": {
1218
+ "mode": "production"
1219
+ }
1220
+ }
1221
+ },
1222
+ "compile": {
1223
+ "executor": "nx:run-commands",
1224
+ "outputs": ["{workspaceRoot}/dist/{projectRoot}/tsc"],
1225
+ "options": {
1226
+ "command": "tsc --build tsconfig.app.json",
1227
+ "cwd": "{projectRoot}"
1228
+ }
1229
+ },
1230
+ "lint": {
1231
+ "executor": "@nx/eslint:lint"
1232
+ },
1233
+ "load:runtime-config": {
1234
+ "executor": "nx:run-commands",
1235
+ "metadata": {
1236
+ "description": "Load runtime config from your deployed stack for dev purposes. You must set your AWS CLI credentials whilst calling 'pnpm exec nx run @proj/test-app:load:runtime-config'"
1237
+ },
1238
+ "options": {
1239
+ "command": "aws s3 cp s3://\`aws cloudformation describe-stacks --query \\"Stacks[?StackName=='proj-infra-sandbox'][].Outputs[?contains(OutputKey, 'WebsiteBucketName')].OutputValue\\" --output text\`/runtime-config.json './test-app/public/runtime-config.json'"
1240
+ }
1241
+ },
1242
+ "preview": {
1243
+ "dependsOn": ["build"],
1244
+ "executor": "@nx/vite:preview-server",
1245
+ "defaultConfiguration": "development",
1246
+ "options": {
1247
+ "buildTarget": "@proj/test-app:build"
1248
+ },
1249
+ "configurations": {
1250
+ "development": {
1251
+ "buildTarget": "@proj/test-app:build:development"
1252
+ },
1253
+ "production": {
1254
+ "buildTarget": "@proj/test-app:build:production"
1255
+ }
1256
+ }
1257
+ },
1258
+ "serve": {
1259
+ "executor": "@nx/vite:dev-server",
1260
+ "defaultConfiguration": "development",
1261
+ "options": {
1262
+ "buildTarget": "@proj/test-app:build"
1263
+ },
1264
+ "configurations": {
1265
+ "development": {
1266
+ "buildTarget": "@proj/test-app:build:development",
1267
+ "hmr": true
1268
+ },
1269
+ "production": {
1270
+ "buildTarget": "@proj/test-app:build:production",
1271
+ "hmr": false
1272
+ }
1273
+ }
1274
+ },
1275
+ "serve-local": {
1276
+ "executor": "@nx/vite:dev-server",
1277
+ "options": {
1278
+ "buildTarget": "@proj/test-app:build:development",
1279
+ "hmr": true,
1280
+ "mode": "serve-local"
1281
+ },
1282
+ "continuous": true
1283
+ },
1284
+ "serve-static": {
1285
+ "executor": "@nx/web:file-server",
1286
+ "dependsOn": ["build"],
1287
+ "options": {
1288
+ "buildTarget": "@proj/test-app:build",
1289
+ "spa": true
1290
+ }
1291
+ },
1292
+ "test": {
1293
+ "executor": "@nx/vite:test",
1294
+ "outputs": ["{options.reportsDirectory}"],
1295
+ "options": {
1296
+ "reportsDirectory": "../coverage/test-app"
1297
+ }
1298
+ }
1299
+ },
1300
+ "metadata": {
1301
+ "generator": "ts#react-website"
1302
+ }
1303
+ }
1304
+ "
1305
+ `;
1306
+
1307
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/public/favicon.ico 1`] = `
1308
+ "00 �%6  ��% h�6(0\` $V/V/cV/�V/�V/�V/�V/�W0�Y1'B#pH[�f��i��i��i��i��i��ia�j�c�^R�\\��Y��U��R�|N�xKuI&V/
1309
+ V/�V/�V/�V/�V/�V/�X1�Y2Ld=9_;�X��l��k��k��k��k��k�kH�c8�a�]��Z��W��S�}P�zM�vIV/
1310
+ V/�V/�V/�V/�V/�W0�Y1�Z3LoD jA�\`;�_=��c��l��k��k��k��k��kÞk�j�f��c��\`��]��Y��V��R�}OCV/
1311
+ V/�V/�V/�V/�V/�W0�Z2�[3LoD[nD�iA�X7�oI��j��k��k��k��k��k��k��m�ks�i��f��b��_��[��W��T�yLV/
1312
+ V/�V/�V/�V/�V/�X1�Z3�\\4MnDoE�qF�oE�f@�X8��Z��l��k��k��k��k��k�ks�k��k��h��d��a��]��Y˅WV/
1313
+ V/�V/�V/�V/�V/�Y1�[3�\\4Ph=nD�pE�rG�sH�oF�a=�cA��f��k��k��k��k��k��k��k��k��j��f��b��_�\\SV/
1314
+ V/�V/�V/�V/�W0�Y2�[4�]5QmC6oD�qF�sH�uJ�uJ�nF�];�wO��k��k��k��k��k��k��k��k��k��h��d��\`��\\V/
1315
+ V/V/
1316
+ V/�V/�V/�V/�W0�Y2�\\4�]5QkA
1317
+ mC�oD�qF�tH�vJ�xL�vK�kD�^=��_��l��k��k��k��k��k��k��k��i��eؔb(V/ V/�V/eV/
1318
+ V/�V/�V/�V/�W0�Z2�\\4�^6QlAXmC�oE�rG�tI�wK�yM�zN�uK�eA�jF��h��k��k��k��k��k��k��k��j��geW0V/RV/�V/
1319
+ V/�V/�V/�V/�W0�Z2�\\4�^6Qj@kA�mC�pE�rG�uI�wK�yM�|O�{O�rJ�^=�|S��k��k��k��k��k��k��k��j��h �Z]5iY1�V/GV/
1320
+ V/�V/�V/�V/�X0�Z2�\\5�^6Qi?kA�mC�pE�rG�uI�wK�zM�|O�}P�xN�eB�W:��c��k��k��k��k��k��o���$W��H��H��KHɦ9�f>�X1�V/�V/
1321
+ V/�V/�V/�V/�X0�Z2�\\4�^6Qg>4i?�kA�mC�pE�rG�uI�wK�zM�|O�|P�vM�b@�bA��g��k��k��k��k��k��s �ӵ]������H-��H���J���G���*�\`8�Y1�V/�V/
1322
+ V/�V/�V/�V/�W0�Z2�\\4�^6Qd; f=�h?�kA�mC�pE�rG�tI�wK�yM�{O�yN�mF�^>��]��l��k��k��k��k��k��l�ͫH��ڔ��ٛ�ؖ�ؖ�ؖ.�ؘr�֏���O�߾D���/��h�i@�]5�Y1�V/�V/
1323
+ V/�V/�V/�V/�W0�Z2�\\4�^5Qd;Uf<�h>�j@�mC�oE�rG�tH�wK�yL�xM�qI�_=�vO��k��k��k��k��k��k��k��j������i��א��ؗ��ؘ��ؗ��֏���k���G��w�mC�e;�a8�]5�X1�V/]V/
1324
+ V/�V/�V/�V/�W0�Y2�\\4�]5Pb:c:�e<�h>�j@�lB�oD�qF�rGDwK}wK�sI�d@�cA��f��k��k��k��k��k��k��k��k��i���$���W���p���v���n���Y���I���*�rG�j@�f<�a8�\\4�X1�V/ V/
1325
+ V/�V/�V/�V/�W0�Y1�[3�\\5Qa8wb:�e<�g>�i@�lB�nD�pE�oCuI}sH�iB�Z:��Z��l��k��k��k��k��k��k��k��j��f��e����Ω4�ܹA�޼B�״=���(�}R�nC�j@�e<�\`8�[4�X1�V/
1326
+ V/�V/�V/�V/�V/�X1�[3�]5�\`7�b9�d;�f=�i?�kA�mC�oD*qG}kD�Z9�oI��j��k��k��k��k��k��k�k��k��i��e��a��]��_��g ��g
1327
+ ��[�xK�rF�nC�i?�d;�_7�[3�X1V/
1328
+ V/�V/�V/�V/�V/�X0�Z2�\\4�_6�a8�c:�f<�h>�j@�lBqjB}_<�\\;��c��l��k��k��k��k��k۞kC�k��j��g��c��\`��\\��X��S�}O�yL�uI�qE�lA�g>�c:�^6�[3JV/
1329
+ V/�V/�V/�V/�V/�W0�Y2�\\4�^6�\`8�b:�e;�g=�i?�kA\`;}U6�U��l��k��k��k��k��k��kl�k$�h��d��a��^��Z��V��S�}O�xK�tH�oD�j@�f<�a9�^6ZS,V/
1330
+ V/�V/�V/�V/�V/�V/�X1�[3�]5�_7�a9�d;�f<�g>MT4~kE��i��k��k��k��k��k��k��k�e�b��_�[��X��T�Q�zM�vJ�rF�mB�i?�e;�a8BW0V/
1331
+ V/�V/�V/�V/�V/�V/�W0�Z2�\\4�^6�\`8�b:�d;�g=iC~�a��k��k��k��k��k��k�k:�\`�]@�Y��VڀR�|O�xK�tH�pD�lA�h>he;V/
1332
+ V/�V/�V/�V/�V/�V/�W0�Y1�[3�]5�_7�a8�c:.xL~Q��R��S��T��T��U��W��o�W�TQ={MTwJYsGJoD+kA V/
1333
+ V/�V/�V/�V/�V/�V/�V/�X0�Z2�\\4�^6�\`7wkA}lB�nC�oD�pF�rG�sH�sH�V/
1334
+ V/�V/�V/�V/�V/�V/�V/�W/�X1�Z3�\\4�^6j@}kA�lB�nC�oD�pE�qF�rG�V/
1335
+ V/�V/�V/�V/�V/�V/�V/�V/�W0�Y2�[3Rh>}i?�j@�lB�mC�nC�oD�pE�V/
1336
+ V/�V/�V/�V/�V/�V/�V/�V/�V/�W0�Z2f=}g=�h?�j@�kA�lB�mB�mC�V/
1337
+ V/�V/�V/�V/�V/�V/�V/�V/�V/�V/2d;}e<�f=�g>�i?�j@�j@�kA�V/
1338
+ V/�V/�V/�V/�V/�V/�V/�V/�V/~b9}c:�d;�e<�f=�g>�h>�i?�V/
1339
+ V/�V/�V/�V/�V/�V/�V/�V/�V/\`7}a8�b9�c:�d;�e<�f<�f=�V/V/TV/pV/nV/nV/nV/nV/oV/:_66\`7oa8nb9nc:nd;nd;pe;C�������������������������������������������������������������������������>�������� ������������?����������������>����\`��\`����������?���?����?����?����?����?���?�?����?����?��������������������������������������������������( @ V/V/XV/\\V/\\V/]X1/L,~SI�i\`�i_�i_�i[�i�_�\\V�X\\�S\\{N^wJ,V/KV/�V/�V/�W0�Y1�d=BgA�b��k��k��k��k��k�s�c��_��Z��U�}P�xL6V/KV/�V/�V/�X1�Z3�pEmC�b=�pJ��j��k��k��k�kJ�kA�g�c��]��X��TyV/KV/�V/�V/�Y1�[3�oDfqF�nE�\`=��Y��l��k��k��kϞk˝j��f��\`��[��VV/KV/�V/�W/�Z2�\\4�mC#oD�rG�uI�lE�hD��e��k��k��k��k��k��h��c�^FV/V/ V/KV/�V/�W0�Z3�]5�h>mC�pE�sH�wK�wL�hC�yP��k��k��k��k��k��i��e��[V/*V/zV/KV/�V/�W0�[3�]5�kA@mB�pE�tI�xL�{N�wL�fC��]��l��k��k��k��j͚g�w ]5\\W0oV/KV/�V/�W0�[3�]5�g>j@�mB�qF�tI�xL�|O�|P�hC�mI��k��k��k��l������F��J ��NIĢ6�d<�V/�V/KV/�V/�W0�[3�]5�g=ci?�mB�pE�tH�xL�{N�wM�eB��[��k��k��k��j���3��ڑU�ݩ�ڜ�ٜF��uk߾Dҽ�1��c�]5�W0�V/KV/�V/�W0�Z3�]5�d;e<�i?�lB�pE�sH�wK�wL�hC�vN��j��k��k��k��j��z�ܿ^��ֈ��׍��Ԃ���Z���!�mC�a8�[4�W0�V/KV/�V/�W/�Z2�\\4�b9�d;�h>�kA�oD�qFBuJ�mE�fB��d��k��k��k��k��k��g��{�Ϊ=�ܽM�ٸD���'�uJ�h>�b9�[3�W06V/KV/�V/�V/�Y1�\\4�\`8�c:�g=�j@�mC�zKlD�_<��W��l��k��k��k��k؝j��f��_��_��e
1340
+ ��] �wK�nC�g=�\`7�[3L'V/KV/�V/�V/�X1�[3�_6�b9�e<�h?�kA%\\9�mG��i��k��k��k��ke�k9�gՔb��]��W�Q�yL�sG�lA�e<�\`7�[3V/KV/�V/�V/�W0�Z2�]5�a8�d;�f=jeA��a��l��l��k��k��k �d.�_��Z�U�}O�vJ�pE�j?�d;v_7V/KV/�V/�V/�V/�X1�\\4�_7�b9�e;|P��Y��Z��[��\\�aA�\\�W7�RnzM�tH�nC\\i?!a9V/KV/�V/�V/�V/�W0�Z2�]5�_7Gj?lA�mC�oD�qF�sG�sH+V/KV/�V/�V/�V/�V/�X1�[3�\`7b8i?�j@�mB�nD�pE�pE+V/KV/�V/�V/�V/�V/�V/�X1)_6f=�g>�i@�kA�lB�mC+V/LV/�V/�V/�V/�V/�V/q]4c:�d;�f=�h>�i?�i?+V/@V/�V/�V/�V/�V/�V/[2\`8�b9�c:�e;�f<�f=$V/V/V/V/V/V/_6\`7a9c:d;d;����������������������������������0��0���������������������00�p8�p?�����������������������������������(  V/'V/;W0*Z3^:�]2�k=�j%�]#�V<{N(j?V/�V/�X1�\\4h@LvM�i��kʞkA�cƉY�QaV/�V/�Z2�[4nCqF�lE��Z��l��k�h��\`��VV/ V/�W0�[3�[4mCrrG�wK�tL��e��k��j�d8��(
1341
+ \\5VV/�W0�[3�f=1kA�rG�zM�qI��^��k��z���z0��#��R^�}#�b:�V/�W0�Z3�d;�j@�qF�qH�zP��j��k��r�ƤB�ڽ]㫆*�lC�[3�V/�V/�Z2�a8�g>�jAGlF“c��l��k��e�a��^�sH�c:�[47V/�V/�X1�^6�c:�^:�TŒa��d��n
1342
+ �\`@�V�xK�mB�d;-V/�V/�V/�Z2�_6 mB
1343
+ mC�pE�sG�yLtHlAV/�V/�V/�W/dc: e<�h?�j@�V/RV/|V/hV/_7a9^d;}f<A��������Oc ������"
1344
+ `;
1345
+
1346
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/src/app.tsx 1`] = `
1347
+ "import AppLayout from './components/AppLayout';
1348
+ import {
1349
+ ContentLayout,
1350
+ Header,
1351
+ SpaceBetween,
1352
+ Container,
1353
+ } from '@cloudscape-design/components';
1354
+
1355
+ export const App = () => (
1356
+ <AppLayout>
1357
+ <ContentLayout header={<Header>Welcome</Header>}>
1358
+ <SpaceBetween size="l">
1359
+ <Container>Welcome to your new React website!</Container>
1360
+ </SpaceBetween>
1361
+ </ContentLayout>
1362
+ </AppLayout>
1363
+ );
1364
+ "
1365
+ `;
1366
+
1367
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/src/components/AppLayout/index.tsx 1`] = `
1368
+ "import * as React from 'react';
1369
+ import { createContext, useCallback, useState } from 'react';
1370
+ import Config from '../../config';
1371
+
1372
+ import { TopNavigation } from '@cloudscape-design/components';
1373
+ import CloudscapeAppLayout, {
1374
+ AppLayoutProps,
1375
+ } from '@cloudscape-design/components/app-layout';
1376
+
1377
+ export interface AppLayoutContext {
1378
+ appLayoutProps: AppLayoutProps;
1379
+ setAppLayoutProps: (props: AppLayoutProps) => void;
1380
+ displayHelpPanel: (helpContent: React.ReactNode) => void;
1381
+ }
1382
+
1383
+ /**
1384
+ * Context for updating/retrieving the AppLayout.
1385
+ */
1386
+ export const AppLayoutContext = createContext({
1387
+ appLayoutProps: {},
1388
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
1389
+ setAppLayoutProps: (_: AppLayoutProps) => {},
1390
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
1391
+ displayHelpPanel: (_: React.ReactNode) => {},
1392
+ });
1393
+
1394
+ /**
1395
+ * Defines the App layout and contains logic for routing.
1396
+ */
1397
+ const AppLayout: React.FC<React.PropsWithChildren> = ({ children }) => {
1398
+ const appLayout = React.useRef<AppLayoutProps.Ref>(null);
1399
+ const [appLayoutProps, setAppLayoutProps] = useState<AppLayoutProps>({});
1400
+ const setAppLayoutPropsSafe = useCallback(
1401
+ (props: AppLayoutProps) => {
1402
+ JSON.stringify(appLayoutProps) !== JSON.stringify(props) &&
1403
+ setAppLayoutProps(props);
1404
+ },
1405
+ [appLayoutProps],
1406
+ );
1407
+
1408
+ return (
1409
+ <AppLayoutContext.Provider
1410
+ value={{
1411
+ appLayoutProps,
1412
+ setAppLayoutProps: setAppLayoutPropsSafe,
1413
+ displayHelpPanel: (helpContent: React.ReactNode) => {
1414
+ setAppLayoutPropsSafe({ tools: helpContent, toolsHide: false });
1415
+ appLayout.current?.openTools();
1416
+ },
1417
+ }}
1418
+ >
1419
+ <TopNavigation
1420
+ identity={{
1421
+ href: '/',
1422
+ title: Config.applicationName,
1423
+ logo: {
1424
+ src: Config.logo,
1425
+ },
1426
+ }}
1427
+ />
1428
+ <CloudscapeAppLayout
1429
+ ref={appLayout}
1430
+ navigationHide
1431
+ toolsHide
1432
+ content={children}
1433
+ {...appLayoutProps}
1434
+ />
1435
+ </AppLayoutContext.Provider>
1436
+ );
1437
+ };
1438
+
1439
+ export default AppLayout;
1440
+ "
1441
+ `;
1442
+
1443
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/src/config.ts 1`] = `
1444
+ "export default {
1445
+ applicationName: 'test-app',
1446
+ logo: 'data:image/svg+xml;base64,PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KDTwhLS0gVXBsb2FkZWQgdG86IFNWRyBSZXBvLCB3d3cuc3ZncmVwby5jb20sIFRyYW5zZm9ybWVkIGJ5OiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4KPHN2ZyBmaWxsPSIjMjQ4YmFlIiB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0cm9rZT0iIzI0OGJhZSI+Cg08ZyBpZD0iU1ZHUmVwb19iZ0NhcnJpZXIiIHN0cm9rZS13aWR0aD0iMCIvPgoNPGcgaWQ9IlNWR1JlcG9fdHJhY2VyQ2FycmllciIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cg08ZyBpZD0iU1ZHUmVwb19pY29uQ2FycmllciI+Cg08dGl0bGU+aW9uaWNvbnMtdjVfbG9nb3M8L3RpdGxlPgoNPHBhdGggZD0iTTQxMC42NiwxODAuNzJoMHEtNy42Ny0yLjYyLTE1LjQ1LTQuODgsMS4yOS01LjI1LDIuMzgtMTAuNTZjMTEuNy01Ni45LDQuMDUtMTAyLjc0LTIyLjA2LTExNy44My0yNS0xNC40OC02NiwuNjEtMTA3LjM2LDM2LjY5cS02LjEsNS4zNC0xMS45NSwxMS0zLjktMy43Ni04LTcuMzZjLTQzLjM1LTM4LjU4LTg2LjgtNTQuODMtMTEyLjg4LTM5LjY5LTI1LDE0LjUxLTMyLjQzLDU3LjYtMjEuOSwxMTEuNTNxMS41OCw4LDMuNTUsMTUuOTNjLTYuMTUsMS43NS0xMi4wOSwzLjYyLTE3Ljc3LDUuNkM0OC40NiwxOTguOSwxNiwyMjYuNzMsMTYsMjU1LjU5YzAsMjkuODIsMzQuODQsNTkuNzIsODcuNzcsNzcuODVxNi40NCwyLjE5LDEzLDQuMDdRMTE0LjY0LDM0NiwxMTMsMzU0LjY4Yy0xMCw1My0yLjIsOTUuMDcsMjIuNzUsMTA5LjQ5LDI1Ljc3LDE0Ljg5LDY5LS40MSwxMTEuMTQtMzcuMzFxNS00LjM4LDEwLTkuMjUsNi4zMiw2LjExLDEzLDExLjg2YzQwLjgsMzUuMTgsODEuMDksNDkuMzksMTA2LDM0LjkzLDI1Ljc1LTE0Ljk0LDM0LjEyLTYwLjE0LDIzLjI1LTExNS4xM3EtMS4yNS02LjMtMi44OC0xMi44Niw0LjU2LTEuMzUsOC45My0yLjc5YzU1LTE4LjI3LDkwLjgzLTQ3LjgxLDkwLjgzLTc4QzQ5NiwyMjYuNjIsNDYyLjUsMTk4LjYxLDQxMC42NiwxODAuNzJabS0xMjktODEuMDhjMzUuNDMtMzAuOTEsNjguNTUtNDMuMTEsODMuNjUtMzQuMzloMGMxNi4wNyw5LjI5LDIyLjMyLDQ2Ljc1LDEyLjIyLDk1Ljg4cS0xLDQuOC0yLjE2LDkuNTdhNDg3LjgzLDQ4Ny44MywwLDAsMC02NC4xOC0xMC4xNiw0ODEuMjcsNDgxLjI3LDAsMCwwLTQwLjU3LTUwLjc1UTI3NiwxMDQuNTcsMjgxLjY0LDk5LjY0Wk0xNTcuNzMsMjgwLjI1cTYuNTEsMTIuNiwxMy42MSwyNC44OSw3LjIzLDEyLjU0LDE1LjA3LDI0LjcxYTQzNS4yOCw0MzUuMjgsMCwwLDEtNDQuMjQtNy4xM0MxNDYuNDEsMzA5LDE1MS42MywyOTQuNzUsMTU3LjczLDI4MC4yNVptMC00OC4zM2MtNi0xNC4xOS0xMS4wOC0yOC4xNS0xNS4yNS00MS42MywxMy43LTMuMDcsMjguMy01LjU4LDQzLjUyLTcuNDhxLTcuNjUsMTEuOTQtMTQuNzIsMjQuMjNUMTU3LjcsMjMxLjkyWm0xMC45LDI0LjE3cTkuNDgtMTkuNzcsMjAuNDItMzguNzhoMHExMC45My0xOSwyMy4yNy0zNy4xM2MxNC4yOC0xLjA4LDI4LjkyLTEuNjUsNDMuNzEtMS42NXMyOS41Mi41Nyw0My43OSwxLjY2cTEyLjIxLDE4LjA5LDIzLjEzLDM3dDIwLjY5LDM4LjZRMzM0LDI3NS42MywzMjMsMjk0LjczaDBxLTEwLjkxLDE5LTIzLDM3LjI0Yy0xNC4yNSwxLTI5LDEuNTUtNDQsMS41NXMtMjkuNDctLjQ3LTQzLjQ2LTEuMzhxLTEyLjQzLTE4LjE5LTIzLjQ2LTM3LjI5VDE2OC42LDI1Ni4wOVpNMzQwLjc1LDMwNXE3LjI1LTEyLjU4LDEzLjkyLTI1LjQ5aDBhNDQwLjQxLDQ0MC40MSwwLDAsMSwxNi4xMiw0Mi4zMkE0MzQuNDQsNDM0LjQ0LDAsMCwxLDMyNiwzMjkuNDhRMzMzLjYyLDMxNy4zOSwzNDAuNzUsMzA1Wm0xMy43Mi03My4wN3EtNi42NC0xMi42NS0xMy44MS0yNWgwcS03LTEyLjE4LTE0LjU5LTI0LjA2YzE1LjMxLDEuOTQsMzAsNC41Miw0My43Nyw3LjY3QTQzOS44OSw0MzkuODksMCwwLDEsMzU0LjQ3LDIzMS45M1pNMjU2LjIzLDEyNC40OGgwYTQzOS43NSw0MzkuNzUsMCwwLDEsMjguMjUsMzQuMThxLTI4LjM1LTEuMzUtNTYuNzQsMEMyMzcuMDcsMTQ2LjMyLDI0Ni42MiwxMzQuODcsMjU2LjIzLDEyNC40OFpNMTQ1LjY2LDY1Ljg2YzE2LjA2LTkuMzIsNTEuNTcsNCw4OSwzNy4yNywyLjM5LDIuMTMsNC44LDQuMzYsNy4yLDYuNjdBNDkxLjM3LDQ5MS4zNywwLDAsMCwyMDEsMTYwLjUxYTQ5OS4xMiw0OTkuMTIsMCwwLDAtNjQuMDYsMTBxLTEuODMtNy4zNi0zLjMtMTQuODJoMEMxMjQuNTksMTA5LjQ2LDEzMC41OCw3NC42MSwxNDUuNjYsNjUuODZaTTEyMi4yNSwzMTcuNzFxLTYtMS43MS0xMS44NS0zLjcxYy0yMy40LTgtNDIuNzMtMTguNDQtNTYtMjkuODFDNDIuNTIsMjc0LDM2LjUsMjYzLjgzLDM2LjUsMjU1LjU5YzAtMTcuNTEsMjYuMDYtMzkuODUsNjkuNTItNTVxOC4xOS0yLjg1LDE2LjUyLTUuMjFhNDkzLjU0LDQ5My41NCwwLDAsMCwyMy40LDYwLjc1QTUwMi40Niw1MDIuNDYsMCwwLDAsMTIyLjI1LDMxNy43MVptMTExLjEzLDkzLjY3Yy0xOC42MywxNi4zMi0zNy4yOSwyNy44OS01My43NCwzMy43MmgwYy0xNC43OCw1LjIzLTI2LjU1LDUuMzgtMzMuNjYsMS4yNy0xNS4xNC04Ljc1LTIxLjQ0LTQyLjU0LTEyLjg1LTg3Ljg2cTEuNTMtOCwzLjUtMTZhNDgwLjg1LDQ4MC44NSwwLDAsMCw2NC42OSw5LjM5LDUwMS4yLDUwMS4yLDAsMCwwLDQxLjIsNTFDMjM5LjU0LDQwNS44MywyMzYuNDksNDA4LjY1LDIzMy4zOCw0MTEuMzhabTIzLjQyLTIzLjIyYy05LjcyLTEwLjUxLTE5LjQyLTIyLjE0LTI4Ljg4LTM0LjY0cTEzLjc5LjU0LDI4LjA4LjU0YzkuNzgsMCwxOS40Ni0uMjEsMjktLjY0QTQzOS4zMyw0MzkuMzMsMCwwLDEsMjU2LjgsMzg4LjE2Wm0xMjQuNTIsMjguNTljLTIuODYsMTUuNDQtOC42MSwyNS43NC0xNS43MiwyOS44Ni0xNS4xMyw4Ljc4LTQ3LjQ4LTIuNjMtODIuMzYtMzIuNzItNC0zLjQ0LTgtNy4xMy0xMi4wNy0xMWE0ODQuNTQsNDg0LjU0LDAsMCwwLDQwLjIzLTUxLjIsNDc3Ljg0LDQ3Ny44NCwwLDAsMCw2NS0xMC4wNXExLjQ3LDUuOTQsMi42LDExLjY0aDBDMzgzLjgxLDM3Ny41OCwzODQuNSwzOTkuNTYsMzgxLjMyLDQxNi43NVptMTcuNC0xMDIuNjRoMGMtMi42Mi44Ny01LjMyLDEuNzEtOC4wNiwyLjUzYTQ4My4yNiw0ODMuMjYsMCwwLDAtMjQuMzEtNjAuOTQsNDgxLjUyLDQ4MS41MiwwLDAsMCwyMy4zNi02MC4wNmM0LjkxLDEuNDMsOS42OCwyLjkzLDE0LjI3LDQuNTIsNDQuNDIsMTUuMzIsNzEuNTIsMzgsNzEuNTIsNTUuNDNDNDc1LjUsMjc0LjE5LDQ0Ni4yMywyOTguMzMsMzk4LjcyLDMxNC4xMVoiLz4KDTxwYXRoIGQ9Ik0yNTYsMjk4LjU1YTQzLDQzLDAsMSwwLTQyLjg2LTQzQTQyLjkxLDQyLjkxLDAsMCwwLDI1NiwyOTguNTVaIi8+Cg08L2c+Cg08L3N2Zz4=',
1447
+ };
1448
+ "
1449
+ `;
1450
+
1451
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/src/hooks/useAppLayout.tsx 1`] = `
1452
+ "import { useContext } from 'react';
1453
+ import { AppLayoutContext } from '../components/AppLayout';
1454
+
1455
+ export const useAppLayout = (): AppLayoutContext =>
1456
+ useContext(AppLayoutContext);
1457
+ "
1458
+ `;
1459
+
1460
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/src/main.tsx 1`] = `
1461
+ "import React from 'react';
1462
+ import { createRoot } from 'react-dom/client';
1463
+ import { I18nProvider } from '@cloudscape-design/components/i18n';
1464
+ import messages from '@cloudscape-design/components/i18n/messages/all.en';
1465
+ import '@cloudscape-design/global-styles/index.css';
1466
+ import { App } from './app';
1467
+
1468
+ const root = document.getElementById('root');
1469
+ root &&
1470
+ createRoot(root).render(
1471
+ <React.StrictMode>
1472
+ <I18nProvider locale="en" messages={[messages]}>
1473
+ <App />
1474
+ </I18nProvider>
1475
+ </React.StrictMode>,
1476
+ );
1477
+ "
1478
+ `;
1479
+
1480
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/src/styles.css 1`] = `
1481
+ "@import 'tailwindcss';
1482
+ /* You can add global styles to this file, and also import other style files */
1483
+ "
1484
+ `;
1485
+
1486
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/tsconfig.app.json 1`] = `
1487
+ "{
1488
+ "extends": "../tsconfig.base.json",
1489
+ "compilerOptions": {
1490
+ "outDir": "../dist/test-app/tsc",
1491
+ "tsBuildInfoFile": "../dist/test-app/tsc/tsconfig.lib.tsbuildinfo",
1492
+ "jsx": "react-jsx",
1493
+ "lib": ["DOM"],
1494
+ "types": [
1495
+ "node",
1496
+ "@nx/react/typings/cssmodule.d.ts",
1497
+ "@nx/react/typings/image.d.ts",
1498
+ "vite/client"
1499
+ ]
1500
+ },
1501
+ "exclude": [
1502
+ "src/**/*.spec.ts",
1503
+ "src/**/*.test.ts",
1504
+ "src/**/*.spec.tsx",
1505
+ "src/**/*.test.tsx",
1506
+ "src/**/*.spec.js",
1507
+ "src/**/*.test.js",
1508
+ "src/**/*.spec.jsx",
1509
+ "src/**/*.test.jsx",
1510
+ "vite.config.ts",
1511
+ "vite.config.mts",
1512
+ "vitest.config.ts",
1513
+ "vitest.config.mts"
1514
+ ],
1515
+ "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
1516
+ }
1517
+ "
1518
+ `;
1519
+
1520
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/tsconfig.json 1`] = `
1521
+ "{
1522
+ "files": [],
1523
+ "include": [],
1524
+ "references": [
1525
+ {
1526
+ "path": "./tsconfig.app.json"
1527
+ },
1528
+ {
1529
+ "path": "./tsconfig.spec.json"
1530
+ }
1531
+ ],
1532
+ "extends": "../tsconfig.base.json",
1533
+ "compilerOptions": {
1534
+ "moduleResolution": "Bundler",
1535
+ "module": "Preserve"
1536
+ }
1537
+ }
1538
+ "
1539
+ `;
1540
+
1541
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/tsconfig.spec.json 1`] = `
1542
+ "{
1543
+ "extends": "../tsconfig.base.json",
1544
+ "compilerOptions": {
1545
+ "outDir": "./out-tsc/vitest",
1546
+ "types": [
1547
+ "vitest/globals",
1548
+ "vitest/importMeta",
1549
+ "vite/client",
1550
+ "node",
1551
+ "vitest",
1552
+ "@nx/react/typings/cssmodule.d.ts",
1553
+ "@nx/react/typings/image.d.ts"
1554
+ ]
1555
+ },
1556
+ "include": [
1557
+ "vite.config.ts",
1558
+ "vite.config.mts",
1559
+ "vitest.config.ts",
1560
+ "vitest.config.mts",
1561
+ "src/**/*.test.ts",
1562
+ "src/**/*.spec.ts",
1563
+ "src/**/*.test.tsx",
1564
+ "src/**/*.spec.tsx",
1565
+ "src/**/*.test.js",
1566
+ "src/**/*.spec.js",
1567
+ "src/**/*.test.jsx",
1568
+ "src/**/*.spec.jsx",
1569
+ "src/**/*.d.ts"
1570
+ ],
1571
+ "references": [
1572
+ {
1573
+ "path": "./tsconfig.app.json"
1574
+ }
1575
+ ]
1576
+ }
1577
+ "
1578
+ `;
1579
+
1580
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/vite.config.ts 1`] = `
1581
+ "import tailwindcss from '@tailwindcss/vite';
1582
+ import tsconfigPaths from 'vite-tsconfig-paths';
1583
+ /// <reference types='vitest' />
1584
+ import { defineConfig } from 'vite';
1585
+ import react from '@vitejs/plugin-react';
1586
+
1587
+ export default defineConfig(() => ({
1588
+ define: {
1589
+ global: {},
1590
+ },
1591
+ root: __dirname,
1592
+ cacheDir: '../node_modules/.vite/test-app',
1593
+ server: {
1594
+ port: 4200,
1595
+ host: 'localhost',
1596
+ },
1597
+ preview: {
1598
+ port: 4300,
1599
+ host: 'localhost',
1600
+ },
1601
+ plugins: [react(), tailwindcss(), tsconfigPaths()],
1602
+ build: {
1603
+ outDir: '../dist/test-app',
1604
+ emptyOutDir: true,
1605
+ reportCompressedSize: true,
1606
+ commonjsOptions: {
1607
+ transformMixedEsModules: true,
1608
+ },
1609
+ },
1610
+ test: {
1611
+ watch: false,
1612
+ globals: true,
1613
+ environment: 'jsdom',
1614
+ include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
1615
+ reporters: ['default'],
1616
+ coverage: {
1617
+ reportsDirectory: './test-output/vitest/coverage',
1618
+ provider: 'v8' as const,
1619
+ },
1620
+ passWithNoTests: true,
1621
+ },
1622
+ }));
1623
+ "
1624
+ `;
1625
+
1626
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > tsconfig.base.json 1`] = `
1627
+ "{
1628
+ "compilerOptions": {
1629
+ "paths": {
1630
+ ":proj/common-types": ["packages/common/types/src/index.ts"],
1631
+ ":proj/test-app": ["test-app/src/index.ts"],
1632
+ ":proj/common-constructs": ["packages/common/constructs/src/index.ts"]
1633
+ },
1634
+ "baseUrl": ".",
1635
+ "rootDir": "."
1636
+ }
1637
+ }
1638
+ "
1639
+ `;
1640
+
1641
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > tsconfig.json 1`] = `
1642
+ "{
1643
+ "references": [
1644
+ {
1645
+ "path": "./test-app"
1646
+ },
1647
+ {
1648
+ "path": "./packages/common/types"
1649
+ },
1650
+ {
1651
+ "path": "./packages/common/constructs"
1652
+ }
1653
+ ]
1654
+ }
1655
+ "
1656
+ `;
1657
+
1658
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > vitest.workspace.ts 1`] = `
1659
+ "export default [
1660
+ '**/vite.config.{mjs,js,ts,mts}',
1661
+ '**/vitest.config.{mjs,js,ts,mts}',
1662
+ ];
1663
+ "
1664
+ `;
1665
+
1666
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > .gitignore 1`] = `
1667
+ "vite.config.*.timestamp*
1668
+ vitest.config.*.timestamp*
1669
+
1670
+ runtime-config.json"
1671
+ `;
1672
+
1673
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > .prettierrc 1`] = `
1674
+ "{ "singleQuote": true }
1675
+ "
1676
+ `;
1677
+
1678
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > eslint.config.mjs 1`] = `
1679
+ "import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
1680
+ import nx from '@nx/eslint-plugin';
1681
+
1682
+ export default [
1683
+ eslintPluginPrettierRecommended,
1684
+ ...nx.configs['flat/base'],
1685
+ ...nx.configs['flat/typescript'],
1686
+ ...nx.configs['flat/javascript'],
1687
+ {
1688
+ ignores: [
1689
+ '**/dist',
1690
+ '**/vite.config.*.timestamp*',
1691
+ '**/vitest.config.*.timestamp*',
1692
+ '**/vite.config.ts.timestamp*',
1693
+ ],
1694
+ },
1695
+ {
1696
+ files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
1697
+ rules: {
1698
+ '@nx/enforce-module-boundaries': [
1699
+ 'error',
1700
+ {
1701
+ enforceBuildableLibDependency: true,
1702
+ allow: ['^.*/eslint(\\\\.base)?\\\\.config\\\\.[cm]?js$'],
1703
+ depConstraints: [
1704
+ {
1705
+ sourceTag: '*',
1706
+ onlyDependOnLibsWithTags: ['*'],
1707
+ },
1708
+ ],
1709
+ },
1710
+ ],
1711
+ },
1712
+ },
1713
+ {
1714
+ files: [
1715
+ '**/*.ts',
1716
+ '**/*.tsx',
1717
+ '**/*.cts',
1718
+ '**/*.mts',
1719
+ '**/*.js',
1720
+ '**/*.jsx',
1721
+ '**/*.cjs',
1722
+ '**/*.mjs',
1723
+ ],
1724
+ rules: {},
1725
+ },
1726
+ ];
1727
+ "
1728
+ `;
1729
+
1730
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > nx.json 1`] = `
1731
+ "{
1732
+ "affected": {
1733
+ "defaultBase": "main"
1734
+ },
1735
+ "targetDefaults": {
1736
+ "build": {
1737
+ "cache": true,
1738
+ "dependsOn": ["^build"],
1739
+ "inputs": ["default"]
1740
+ },
1741
+ "lint": {
1742
+ "cache": true,
1743
+ "configurations": {
1744
+ "fix": {
1745
+ "fix": true
1746
+ }
1747
+ },
1748
+ "inputs": [
1749
+ "default",
1750
+ "{workspaceRoot}/eslint.config.mjs",
1751
+ "{projectRoot}/eslint.config.mjs"
1752
+ ]
1753
+ },
1754
+ "@nx/eslint:lint": {
1755
+ "cache": true,
1756
+ "inputs": [
1757
+ "default",
1758
+ "{workspaceRoot}/.eslintrc.json",
1759
+ "{workspaceRoot}/.eslintignore",
1760
+ "{workspaceRoot}/eslint.config.mjs"
1761
+ ]
1762
+ },
1763
+ "@nx/vite:test": {
1764
+ "cache": true,
1765
+ "inputs": ["default", "^default"],
1766
+ "configurations": {
1767
+ "update-snapshot": {
1768
+ "args": "--update"
1769
+ }
1770
+ }
1771
+ },
1772
+ "@nx/vite:build": {
1773
+ "cache": true,
1774
+ "dependsOn": ["^build"],
1775
+ "inputs": ["default", "^default"]
1776
+ },
1777
+ "test": {
1778
+ "dependsOn": ["^build"],
1779
+ "inputs": ["default"]
1780
+ },
1781
+ "compile": {
1782
+ "cache": true,
1783
+ "inputs": ["default"]
1784
+ }
1785
+ },
1786
+ "generators": {
1787
+ "@nx/react": {
1788
+ "application": {
1789
+ "babel": true,
1790
+ "style": "css",
1791
+ "linter": "eslint",
1792
+ "bundler": "vite"
1793
+ },
1794
+ "component": {
1795
+ "style": "css"
1796
+ },
1797
+ "library": {
1798
+ "style": "css",
1799
+ "linter": "eslint"
1800
+ }
1801
+ }
1802
+ },
1803
+ "plugins": [
1804
+ {
1805
+ "plugin": "@nx/js/typescript",
1806
+ "options": {
1807
+ "typecheck": {
1808
+ "targetName": "typecheck"
1809
+ },
1810
+ "build": {
1811
+ "targetName": "compile",
1812
+ "configName": "tsconfig.lib.json",
1813
+ "buildDepsName": "build-deps",
1814
+ "watchDepsName": "watch-deps"
1815
+ }
1816
+ }
1817
+ },
1818
+ {
1819
+ "plugin": "@nx/eslint/plugin",
1820
+ "options": {
1821
+ "targetName": "lint"
1822
+ }
1823
+ }
1824
+ ],
1825
+ "namedInputs": {
1826
+ "default": [
1827
+ {
1828
+ "dependentTasksOutputFiles": "**/*",
1829
+ "transitive": true
1830
+ }
1831
+ ]
1832
+ }
1833
+ }
1834
+ "
1835
+ `;
1836
+
1837
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > package.json 1`] = `
1838
+ "{
1839
+ "name": "@proj/source",
1840
+ "dependencies": {
1841
+ "@cloudscape-design/board-components": "^3.0.94",
1842
+ "@cloudscape-design/components": "^3.0.928",
1843
+ "@cloudscape-design/global-styles": "^1.0.38",
1844
+ "@tanstack/react-router": "^1.121.16",
1845
+ "aws-cdk-lib": "^2.200.0",
1846
+ "constructs": "^10.4.2",
1847
+ "react": "19.0.0",
1848
+ "react-dom": "19.0.0",
1849
+ "tailwindcss": "^4.1.11"
1850
+ },
1851
+ "devDependencies": {
1852
+ "@eslint/js": "^9.8.0",
1853
+ "@nx/eslint": "21.0.3",
1854
+ "@nx/eslint-plugin": "21.0.3",
1855
+ "@nx/js": "21.0.3",
1856
+ "@nx/react": "21.0.3",
1857
+ "@nx/vite": "21.0.3",
1858
+ "@nx/web": "21.0.3",
1859
+ "@swc-node/register": "~1.9.1",
1860
+ "@swc/cli": "~0.6.0",
1861
+ "@swc/core": "~1.5.7",
1862
+ "@swc/helpers": "~0.5.11",
1863
+ "@tailwindcss/vite": "^4.1.11",
1864
+ "@tanstack/router-generator": "^1.121.16",
1865
+ "@tanstack/router-plugin": "^1.121.16",
1866
+ "@tanstack/router-utils": "^1.121.0",
1867
+ "@tanstack/virtual-file-routes": "^1.120.17",
1868
+ "@testing-library/dom": "10.4.0",
1869
+ "@testing-library/react": "16.1.0",
1870
+ "@types/node": "^22.13.13",
1871
+ "@types/react": "19.0.0",
1872
+ "@types/react-dom": "19.0.0",
1873
+ "@vitejs/plugin-react": "^4.2.0",
1874
+ "@vitest/coverage-v8": "^3.0.5",
1875
+ "@vitest/ui": "^3.0.0",
1876
+ "eslint": "^9.8.0",
1877
+ "eslint-config-prettier": "^10.0.0",
1878
+ "eslint-plugin-import": "2.31.0",
1879
+ "eslint-plugin-jsx-a11y": "6.10.1",
1880
+ "eslint-plugin-prettier": "^5.2.5",
1881
+ "eslint-plugin-react": "7.35.0",
1882
+ "eslint-plugin-react-hooks": "5.0.0",
1883
+ "jiti": "2.4.2",
1884
+ "jsdom": "~22.1.0",
1885
+ "jsonc-eslint-parser": "^2.4.0",
1886
+ "prettier": "^3.5.3",
1887
+ "typescript": "~5.7.2",
1888
+ "typescript-eslint": "^8.19.0",
1889
+ "vite": "^6.0.0",
1890
+ "vite-tsconfig-paths": "^5.1.4",
1891
+ "vitest": "^3.0.0"
1892
+ },
1893
+ "type": "module"
1894
+ }
1895
+ "
1896
+ `;
1897
+
1898
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/constructs/README.md 1`] = `
1899
+ "# @proj/common-constructs
1900
+
1901
+ This library was generated with [@aws/nx-plugin](https://github.com/awslabs/nx-plugin-for-aws/).
1902
+
1903
+ ## Building
1904
+
1905
+ Run \`npx nx build @proj/common-constructs [--skip-nx-cache]\` to build the application.
1906
+
1907
+ ## Running unit tests
1908
+
1909
+ Run \`npx nx test @proj/common-constructs\` to execute the unit tests via Vitest.
1910
+
1911
+ ### Updating snapshots
1912
+
1913
+ To update snapshots, run the following command:
1914
+
1915
+ \`npx nx test @proj/common-constructs --configuration=update-snapshot\`
1916
+
1917
+ ## Run lint
1918
+
1919
+ Run \`npx nx lint @proj/common-constructs\`
1920
+
1921
+ ### Fixable issues
1922
+
1923
+ You can also automatiaclly fix some lint errors by running the following command:
1924
+
1925
+ \`npx nx lint @proj/common-constructs --configuration=fix\`
1926
+
1927
+ ## Useful links
1928
+
1929
+ - [common-constructs reference docs](TODO)
1930
+ - [Learn more about NX](https://nx.dev/getting-started/intro)
1931
+ "
1932
+ `;
1933
+
1934
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/constructs/eslint.config.mjs 1`] = `
1935
+ "import baseConfig from '../../../eslint.config.mjs';
1936
+
1937
+ export default [
1938
+ ...baseConfig,
1939
+ {
1940
+ files: ['**/*.json'],
1941
+ rules: {
1942
+ '@nx/dependency-checks': [
1943
+ 'warn',
1944
+ {
1945
+ ignoredFiles: [
1946
+ '{projectRoot}/eslint.config.{js,cjs,mjs}',
1947
+ '{projectRoot}/vite.config.{js,ts,mjs,mts}',
1948
+ ],
1949
+ },
1950
+ ],
1951
+ },
1952
+ languageOptions: {
1953
+ parser: await import('jsonc-eslint-parser'),
1954
+ },
1955
+ },
1956
+ ];
1957
+ "
1958
+ `;
1959
+
1960
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/constructs/project.json 1`] = `
1961
+ "{
1962
+ "name": "@proj/common-constructs",
1963
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
1964
+ "sourceRoot": "packages/common/constructs/src",
1965
+ "projectType": "library",
1966
+ "tags": [],
1967
+ "targets": {
1968
+ "build": {
1969
+ "dependsOn": ["lint", "compile", "test", "@proj/test-app:build"]
1970
+ },
1971
+ "compile": {
1972
+ "executor": "nx:run-commands",
1973
+ "outputs": ["{workspaceRoot}/dist/packages/common/constructs/tsc"],
1974
+ "options": {
1975
+ "command": "tsc --build tsconfig.lib.json",
1976
+ "cwd": "{projectRoot}"
1977
+ }
1978
+ },
1979
+ "test": {
1980
+ "executor": "@nx/vite:test",
1981
+ "outputs": ["{options.reportsDirectory}"],
1982
+ "options": {
1983
+ "reportsDirectory": "../../../coverage/packages/common/constructs"
1984
+ }
1985
+ }
1986
+ },
1987
+ "metadata": {
1988
+ "generator": "ts#project"
1989
+ }
1990
+ }
1991
+ "
1992
+ `;
1993
+
1994
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/constructs/src/app/index.ts 1`] = `
1995
+ "export * from './static-websites/index.js';
1996
+ "
1997
+ `;
1998
+
1999
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/constructs/src/app/static-websites/index.ts 1`] = `
2000
+ "export * from './test-app.js';
2001
+ "
2002
+ `;
2003
+
2004
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/constructs/src/app/static-websites/test-app.ts 1`] = `
2005
+ "import * as url from 'url';
2006
+ import { Construct } from 'constructs';
2007
+ import { StaticWebsite } from '../../core/index.js';
2008
+
2009
+ export class TestApp extends StaticWebsite {
2010
+ constructor(scope: Construct, id: string) {
2011
+ super(scope, id, {
2012
+ websiteFilePath: url.fileURLToPath(
2013
+ new URL('../../../../../../dist/test-app/bundle', import.meta.url),
2014
+ ),
2015
+ });
2016
+ }
2017
+ }
2018
+ "
2019
+ `;
2020
+
2021
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/constructs/src/core/app.ts 1`] = `
2022
+ "import { App as _App, AppProps, Aspects, IAspect, Stack } from 'aws-cdk-lib';
2023
+ import { IConstruct } from 'constructs';
2024
+
2025
+ export class App extends _App {
2026
+ constructor(props?: AppProps) {
2027
+ super(props);
2028
+
2029
+ Aspects.of(this).add(new MetricsAspect());
2030
+ }
2031
+ }
2032
+
2033
+ /**
2034
+ * Adds information to CloudFormation stack descriptions to provide usage metrics for @aws/nx-plugin
2035
+ */
2036
+ class MetricsAspect implements IAspect {
2037
+ visit(node: IConstruct): void {
2038
+ if (node instanceof Stack) {
2039
+ const id = 'uksb-4wk0bqpg5s';
2040
+ const version = '0.0.0';
2041
+ const tags: string[] = ['g5'];
2042
+ node.templateOptions.description =
2043
+ \`\${node.templateOptions.description ?? ''} (\${id}) (version:\${version}) (tag:\${tags.join(',')})\`.trim();
2044
+ }
2045
+ }
2046
+ }
2047
+ "
2048
+ `;
2049
+
2050
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/constructs/src/core/index.ts 1`] = `
2051
+ "export * from './static-website.js';
2052
+ export * from './app.js';
2053
+ export * from './runtime-config.js';
2054
+ "
2055
+ `;
2056
+
2057
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/constructs/src/core/runtime-config.ts 1`] = `
2058
+ "import type { IRuntimeConfig } from ':proj/common-types';
2059
+ import { Stack } from 'aws-cdk-lib';
2060
+ import { Construct } from 'constructs';
2061
+
2062
+ const RuntimeConfigKey = '__RuntimeConfig__';
2063
+
2064
+ export class RuntimeConfig extends Construct {
2065
+ private readonly _runtimeConfig: Partial<IRuntimeConfig> = {};
2066
+
2067
+ static ensure(scope: Construct): RuntimeConfig {
2068
+ const stack = Stack.of(scope);
2069
+ return (
2070
+ RuntimeConfig.of(scope) ?? new RuntimeConfig(stack, RuntimeConfigKey)
2071
+ );
2072
+ }
2073
+
2074
+ static of(scope: Construct): RuntimeConfig | undefined {
2075
+ const stack = Stack.of(scope);
2076
+ return stack.node.tryFindChild(RuntimeConfigKey) as
2077
+ | RuntimeConfig
2078
+ | undefined;
2079
+ }
2080
+
2081
+ constructor(scope: Construct, id: string) {
2082
+ super(scope, id);
2083
+ }
2084
+
2085
+ get config(): Partial<IRuntimeConfig> {
2086
+ return this._runtimeConfig;
2087
+ }
2088
+ }
2089
+ "
2090
+ `;
2091
+
2092
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/constructs/src/core/static-website.ts 1`] = `
2093
+ "import { CfnJson, CfnOutput, RemovalPolicy, Stack, Token } from 'aws-cdk-lib';
2094
+ import { Distribution, ViewerProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
2095
+ import { S3BucketOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
2096
+ import {
2097
+ BlockPublicAccess,
2098
+ Bucket,
2099
+ BucketEncryption,
2100
+ IBucket,
2101
+ ObjectOwnership,
2102
+ } from 'aws-cdk-lib/aws-s3';
2103
+ import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';
2104
+ import { Construct } from 'constructs';
2105
+ import { RuntimeConfig } from './runtime-config.js';
2106
+ import { Key } from 'aws-cdk-lib/aws-kms';
2107
+ import { CfnWebACL } from 'aws-cdk-lib/aws-wafv2';
2108
+ const DEFAULT_RUNTIME_CONFIG_FILENAME = 'runtime-config.json';
2109
+
2110
+ export interface StaticWebsiteProps {
2111
+ readonly websiteFilePath: string;
2112
+ }
2113
+
2114
+ /**
2115
+ * Deploys a Static Website using by default a private S3 bucket as an origin and Cloudfront as the entrypoint.
2116
+ *
2117
+ * This construct configures a webAcl containing rules that are generally applicable to web applications. This
2118
+ * provides protection against exploitation of a wide range of vulnerabilities, including some of the high risk
2119
+ * and commonly occurring vulnerabilities described in OWASP publications such as OWASP Top 10.
2120
+ *
2121
+ */
2122
+ export class StaticWebsite extends Construct {
2123
+ public readonly websiteBucket: IBucket;
2124
+ public readonly cloudFrontDistribution: Distribution;
2125
+ public readonly bucketDeployment: BucketDeployment;
2126
+
2127
+ constructor(
2128
+ scope: Construct,
2129
+ id: string,
2130
+ { websiteFilePath }: StaticWebsiteProps,
2131
+ ) {
2132
+ super(scope, id);
2133
+ this.node.setContext(
2134
+ '@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy',
2135
+ true,
2136
+ );
2137
+
2138
+ const websiteKey = new Key(this, 'WebsiteKey', {
2139
+ enableKeyRotation: true,
2140
+ });
2141
+
2142
+ const accessLogsBucket = new Bucket(this, 'AccessLogsBucket', {
2143
+ versioned: false,
2144
+ enforceSSL: true,
2145
+ autoDeleteObjects: true,
2146
+ removalPolicy: RemovalPolicy.DESTROY,
2147
+ encryption: BucketEncryption.KMS,
2148
+ encryptionKey: websiteKey,
2149
+ objectOwnership: ObjectOwnership.OBJECT_WRITER,
2150
+ publicReadAccess: false,
2151
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
2152
+ });
2153
+ // S3 Bucket to hold website files
2154
+ this.websiteBucket = new Bucket(this, 'WebsiteBucket', {
2155
+ versioned: true,
2156
+ enforceSSL: true,
2157
+ autoDeleteObjects: true,
2158
+ removalPolicy: RemovalPolicy.DESTROY,
2159
+ encryption: BucketEncryption.KMS,
2160
+ encryptionKey: websiteKey,
2161
+ objectOwnership: ObjectOwnership.BUCKET_OWNER_ENFORCED,
2162
+ publicReadAccess: false,
2163
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
2164
+ serverAccessLogsPrefix: 'website-access-logs',
2165
+ serverAccessLogsBucket: accessLogsBucket,
2166
+ });
2167
+ // Web ACL
2168
+ const wafStack = new CloudfrontWebAcl(this, 'waf');
2169
+
2170
+ // Cloudfront Distribution
2171
+ const logBucket = new Bucket(this, 'DistributionLogBucket', {
2172
+ enforceSSL: true,
2173
+ autoDeleteObjects: true,
2174
+ removalPolicy: RemovalPolicy.DESTROY,
2175
+ encryption: BucketEncryption.KMS,
2176
+ encryptionKey: websiteKey,
2177
+ objectOwnership: ObjectOwnership.BUCKET_OWNER_PREFERRED,
2178
+ publicReadAccess: false,
2179
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
2180
+ serverAccessLogsPrefix: 'distribution-access-logs',
2181
+ serverAccessLogsBucket: accessLogsBucket,
2182
+ });
2183
+ const defaultRootObject = 'index.html';
2184
+ this.cloudFrontDistribution = new Distribution(
2185
+ this,
2186
+ 'CloudfrontDistribution',
2187
+ {
2188
+ webAclId: wafStack.wafArn,
2189
+ enableLogging: true,
2190
+ logBucket: logBucket,
2191
+ defaultBehavior: {
2192
+ origin: S3BucketOrigin.withOriginAccessControl(this.websiteBucket),
2193
+ viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
2194
+ },
2195
+ defaultRootObject,
2196
+ errorResponses: [
2197
+ {
2198
+ httpStatus: 404, // We need to redirect "key not found errors" to index.html for single page apps
2199
+ responseHttpStatus: 200,
2200
+ responsePagePath: \`/\${defaultRootObject}\`,
2201
+ },
2202
+ {
2203
+ httpStatus: 403, // We need to redirect reloads from paths (e.g. /foo/bar) to index.html for single page apps
2204
+ responseHttpStatus: 200,
2205
+ responsePagePath: \`/\${defaultRootObject}\`,
2206
+ },
2207
+ ],
2208
+ },
2209
+ );
2210
+ // Deploy Website
2211
+ this.bucketDeployment = new BucketDeployment(this, 'WebsiteDeployment', {
2212
+ sources: [
2213
+ Source.asset(websiteFilePath),
2214
+ Source.jsonData(
2215
+ DEFAULT_RUNTIME_CONFIG_FILENAME,
2216
+ this.resolveTokens(RuntimeConfig.ensure(this).config),
2217
+ ),
2218
+ ],
2219
+ destinationBucket: this.websiteBucket,
2220
+ // Files in the distribution's edge caches will be invalidated after files are uploaded to the destination bucket.
2221
+ distribution: this.cloudFrontDistribution,
2222
+ memoryLimit: 1024,
2223
+ });
2224
+ new CfnOutput(this, 'DistributionDomainName', {
2225
+ value: this.cloudFrontDistribution.domainName,
2226
+ });
2227
+ new CfnOutput(this, 'WebsiteBucketName', {
2228
+ value: this.websiteBucket.bucketName,
2229
+ });
2230
+ }
2231
+ private resolveTokens = (payload: any) => {
2232
+ const _payload: Record<string, any> = {};
2233
+ Object.entries(payload).forEach(([key, value]) => {
2234
+ if (
2235
+ Token.isUnresolved(value) ||
2236
+ (typeof value === 'string' && value.endsWith('}}'))
2237
+ ) {
2238
+ _payload[key] = new CfnJson(this, \`ResolveToken-\${key}\`, {
2239
+ value,
2240
+ }).value;
2241
+ } else if (typeof value === 'object') {
2242
+ _payload[key] = this.resolveTokens(value);
2243
+ } else if (Array.isArray(value)) {
2244
+ _payload[key] = value.map((v) => this.resolveTokens(v));
2245
+ } else {
2246
+ _payload[key] = value;
2247
+ }
2248
+ });
2249
+ return _payload;
2250
+ };
2251
+ }
2252
+
2253
+ export class CloudfrontWebAcl extends Stack {
2254
+ public readonly wafArn;
2255
+ constructor(scope: Construct, id: string) {
2256
+ super(scope, id, {
2257
+ env: {
2258
+ region: 'us-east-1',
2259
+ account: Stack.of(scope).account,
2260
+ },
2261
+ crossRegionReferences: true,
2262
+ });
2263
+
2264
+ this.wafArn = new CfnWebACL(this, 'WebAcl', {
2265
+ defaultAction: { allow: {} },
2266
+ scope: 'CLOUDFRONT',
2267
+ visibilityConfig: {
2268
+ cloudWatchMetricsEnabled: true,
2269
+ metricName: id,
2270
+ sampledRequestsEnabled: true,
2271
+ },
2272
+ rules: [
2273
+ {
2274
+ name: 'CRSRule',
2275
+ priority: 0,
2276
+ statement: {
2277
+ managedRuleGroupStatement: {
2278
+ name: 'AWSManagedRulesCommonRuleSet',
2279
+ vendorName: 'AWS',
2280
+ },
2281
+ },
2282
+ visibilityConfig: {
2283
+ cloudWatchMetricsEnabled: true,
2284
+ metricName: 'MetricForWebACLCDK-CRS',
2285
+ sampledRequestsEnabled: true,
2286
+ },
2287
+ overrideAction: {
2288
+ none: {},
2289
+ },
2290
+ },
2291
+ ],
2292
+ }).attrArn;
2293
+ }
2294
+ }
2295
+ "
2296
+ `;
2297
+
2298
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/constructs/src/index.ts 1`] = `
2299
+ "export * from './app/index.js';
2300
+ export * from './core/index.js';
2301
+ "
2302
+ `;
2303
+
2304
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/constructs/tsconfig.json 1`] = `
2305
+ "{
2306
+ "extends": "../../../tsconfig.base.json",
2307
+ "files": [],
2308
+ "include": [],
2309
+ "references": [
2310
+ {
2311
+ "path": "./tsconfig.lib.json"
2312
+ },
2313
+ {
2314
+ "path": "./tsconfig.spec.json"
2315
+ }
2316
+ ],
2317
+ "compilerOptions": {}
2318
+ }
2319
+ "
2320
+ `;
2321
+
2322
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/constructs/tsconfig.lib.json 1`] = `
2323
+ "{
2324
+ "extends": "../../../tsconfig.base.json",
2325
+ "compilerOptions": {
2326
+ "rootDir": ".",
2327
+ "outDir": "../../../dist/packages/common/constructs/tsc",
2328
+ "tsBuildInfoFile": "../../../dist/packages/common/constructs/tsc/tsconfig.lib.tsbuildinfo",
2329
+ "emitDeclarationOnly": false,
2330
+ "module": "nodenext",
2331
+ "moduleResolution": "nodenext",
2332
+ "types": ["node"]
2333
+ },
2334
+ "include": ["src/**/*.ts"],
2335
+ "references": [],
2336
+ "exclude": [
2337
+ "vite.config.ts",
2338
+ "vite.config.mts",
2339
+ "vitest.config.ts",
2340
+ "vitest.config.mts",
2341
+ "src/**/*.test.ts",
2342
+ "src/**/*.spec.ts",
2343
+ "src/**/*.test.tsx",
2344
+ "src/**/*.spec.tsx",
2345
+ "src/**/*.test.js",
2346
+ "src/**/*.spec.js",
2347
+ "src/**/*.test.jsx",
2348
+ "src/**/*.spec.jsx"
2349
+ ]
2350
+ }
2351
+ "
2352
+ `;
2353
+
2354
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/constructs/tsconfig.spec.json 1`] = `
2355
+ "{
2356
+ "extends": "../../../tsconfig.base.json",
2357
+ "compilerOptions": {
2358
+ "outDir": "./out-tsc/vitest",
2359
+ "types": [
2360
+ "vitest/globals",
2361
+ "vitest/importMeta",
2362
+ "vite/client",
2363
+ "node",
2364
+ "vitest"
2365
+ ],
2366
+ "module": "nodenext",
2367
+ "moduleResolution": "nodenext"
2368
+ },
2369
+ "include": [
2370
+ "vite.config.ts",
2371
+ "vite.config.mts",
2372
+ "vitest.config.ts",
2373
+ "vitest.config.mts",
2374
+ "src/**/*.test.ts",
2375
+ "src/**/*.spec.ts",
2376
+ "src/**/*.test.tsx",
2377
+ "src/**/*.spec.tsx",
2378
+ "src/**/*.test.js",
2379
+ "src/**/*.spec.js",
2380
+ "src/**/*.test.jsx",
2381
+ "src/**/*.spec.jsx",
2382
+ "src/**/*.d.ts"
2383
+ ],
2384
+ "references": [
2385
+ {
2386
+ "path": "./tsconfig.lib.json"
2387
+ }
2388
+ ]
2389
+ }
2390
+ "
2391
+ `;
2392
+
2393
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/constructs/vite.config.ts 1`] = `
2394
+ "import { defineConfig } from 'vite';
2395
+
2396
+ export default defineConfig(() => ({
2397
+ root: __dirname,
2398
+ cacheDir: '../../../node_modules/.vite/packages/common/constructs',
2399
+ plugins: [],
2400
+ // Uncomment this if you are using workers.
2401
+ // worker: {
2402
+ // plugins: [ nxViteTsPaths() ],
2403
+ // },
2404
+ test: {
2405
+ watch: false,
2406
+ globals: true,
2407
+ environment: 'jsdom',
2408
+ include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
2409
+ reporters: ['default'],
2410
+ coverage: {
2411
+ reportsDirectory: './test-output/vitest/coverage',
2412
+ provider: 'v8' as const,
2413
+ },
2414
+ passWithNoTests: true,
2415
+ },
2416
+ }));
2417
+ "
2418
+ `;
2419
+
2420
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/types/README.md 1`] = `
2421
+ "# @proj/common-types
2422
+
2423
+ This library was generated with [@aws/nx-plugin](https://github.com/awslabs/nx-plugin-for-aws/).
2424
+
2425
+ ## Building
2426
+
2427
+ Run \`npx nx build @proj/common-types [--skip-nx-cache]\` to build the application.
2428
+
2429
+ ## Running unit tests
2430
+
2431
+ Run \`npx nx test @proj/common-types\` to execute the unit tests via Vitest.
2432
+
2433
+ ### Updating snapshots
2434
+
2435
+ To update snapshots, run the following command:
2436
+
2437
+ \`npx nx test @proj/common-types --configuration=update-snapshot\`
2438
+
2439
+ ## Run lint
2440
+
2441
+ Run \`npx nx lint @proj/common-types\`
2442
+
2443
+ ### Fixable issues
2444
+
2445
+ You can also automatiaclly fix some lint errors by running the following command:
2446
+
2447
+ \`npx nx lint @proj/common-types --configuration=fix\`
2448
+
2449
+ ## Useful links
2450
+
2451
+ - [common-types reference docs](TODO)
2452
+ - [Learn more about NX](https://nx.dev/getting-started/intro)
2453
+ "
2454
+ `;
2455
+
2456
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/types/eslint.config.mjs 1`] = `
2457
+ "import baseConfig from '../../../eslint.config.mjs';
2458
+
2459
+ export default [
2460
+ ...baseConfig,
2461
+ {
2462
+ files: ['**/*.json'],
2463
+ rules: {
2464
+ '@nx/dependency-checks': [
2465
+ 'warn',
2466
+ {
2467
+ ignoredFiles: [
2468
+ '{projectRoot}/eslint.config.{js,cjs,mjs}',
2469
+ '{projectRoot}/vite.config.{js,ts,mjs,mts}',
2470
+ ],
2471
+ },
2472
+ ],
2473
+ },
2474
+ languageOptions: {
2475
+ parser: await import('jsonc-eslint-parser'),
2476
+ },
2477
+ },
2478
+ ];
2479
+ "
2480
+ `;
2481
+
2482
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/types/project.json 1`] = `
2483
+ "{
2484
+ "name": "@proj/common-types",
2485
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
2486
+ "sourceRoot": "packages/common/types/src",
2487
+ "projectType": "library",
2488
+ "tags": [],
2489
+ "targets": {
2490
+ "build": {
2491
+ "dependsOn": ["lint", "compile", "test"]
2492
+ },
2493
+ "compile": {
2494
+ "executor": "nx:run-commands",
2495
+ "outputs": ["{workspaceRoot}/dist/packages/common/types/tsc"],
2496
+ "options": {
2497
+ "command": "tsc --build tsconfig.lib.json",
2498
+ "cwd": "{projectRoot}"
2499
+ }
2500
+ },
2501
+ "test": {
2502
+ "executor": "@nx/vite:test",
2503
+ "outputs": ["{options.reportsDirectory}"],
2504
+ "options": {
2505
+ "reportsDirectory": "../../../coverage/packages/common/types"
2506
+ }
2507
+ }
2508
+ },
2509
+ "metadata": {
2510
+ "generator": "ts#project"
2511
+ }
2512
+ }
2513
+ "
2514
+ `;
2515
+
2516
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/types/src/index.ts 1`] = `
2517
+ "export * from './runtime-config.js';
2518
+ "
2519
+ `;
2520
+
2521
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/types/src/runtime-config.ts 1`] = `
2522
+ "// eslint-disable-next-line @typescript-eslint/no-empty-object-type, @typescript-eslint/no-empty-interface
2523
+ export interface IRuntimeConfig {}
2524
+ "
2525
+ `;
2526
+
2527
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/types/tsconfig.json 1`] = `
2528
+ "{
2529
+ "extends": "../../../tsconfig.base.json",
2530
+ "files": [],
2531
+ "include": [],
2532
+ "references": [
2533
+ {
2534
+ "path": "./tsconfig.lib.json"
2535
+ },
2536
+ {
2537
+ "path": "./tsconfig.spec.json"
2538
+ }
2539
+ ],
2540
+ "compilerOptions": {}
2541
+ }
2542
+ "
2543
+ `;
2544
+
2545
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/types/tsconfig.lib.json 1`] = `
2546
+ "{
2547
+ "extends": "../../../tsconfig.base.json",
2548
+ "compilerOptions": {
2549
+ "rootDir": ".",
2550
+ "outDir": "../../../dist/packages/common/types/tsc",
2551
+ "tsBuildInfoFile": "../../../dist/packages/common/types/tsc/tsconfig.lib.tsbuildinfo",
2552
+ "emitDeclarationOnly": false,
2553
+ "module": "nodenext",
2554
+ "moduleResolution": "nodenext",
2555
+ "types": ["node"]
2556
+ },
2557
+ "include": ["src/**/*.ts"],
2558
+ "references": [],
2559
+ "exclude": [
2560
+ "vite.config.ts",
2561
+ "vite.config.mts",
2562
+ "vitest.config.ts",
2563
+ "vitest.config.mts",
2564
+ "src/**/*.test.ts",
2565
+ "src/**/*.spec.ts",
2566
+ "src/**/*.test.tsx",
2567
+ "src/**/*.spec.tsx",
2568
+ "src/**/*.test.js",
2569
+ "src/**/*.spec.js",
2570
+ "src/**/*.test.jsx",
2571
+ "src/**/*.spec.jsx"
2572
+ ]
2573
+ }
2574
+ "
2575
+ `;
2576
+
2577
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/types/tsconfig.spec.json 1`] = `
2578
+ "{
2579
+ "extends": "../../../tsconfig.base.json",
2580
+ "compilerOptions": {
2581
+ "outDir": "./out-tsc/vitest",
2582
+ "types": [
2583
+ "vitest/globals",
2584
+ "vitest/importMeta",
2585
+ "vite/client",
2586
+ "node",
2587
+ "vitest"
2588
+ ],
2589
+ "module": "nodenext",
2590
+ "moduleResolution": "nodenext"
2591
+ },
2592
+ "include": [
2593
+ "vite.config.ts",
2594
+ "vite.config.mts",
2595
+ "vitest.config.ts",
2596
+ "vitest.config.mts",
2597
+ "src/**/*.test.ts",
2598
+ "src/**/*.spec.ts",
2599
+ "src/**/*.test.tsx",
2600
+ "src/**/*.spec.tsx",
2601
+ "src/**/*.test.js",
2602
+ "src/**/*.spec.js",
2603
+ "src/**/*.test.jsx",
2604
+ "src/**/*.spec.jsx",
2605
+ "src/**/*.d.ts"
2606
+ ],
2607
+ "references": [
2608
+ {
2609
+ "path": "./tsconfig.lib.json"
2610
+ }
2611
+ ]
2612
+ }
2613
+ "
2614
+ `;
2615
+
2616
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/types/vite.config.ts 1`] = `
2617
+ "import { defineConfig } from 'vite';
2618
+
2619
+ export default defineConfig(() => ({
2620
+ root: __dirname,
2621
+ cacheDir: '../../../node_modules/.vite/packages/common/types',
2622
+ plugins: [],
2623
+ // Uncomment this if you are using workers.
2624
+ // worker: {
2625
+ // plugins: [ nxViteTsPaths() ],
2626
+ // },
2627
+ test: {
2628
+ watch: false,
2629
+ globals: true,
2630
+ environment: 'jsdom',
2631
+ include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
2632
+ reporters: ['default'],
2633
+ coverage: {
2634
+ reportsDirectory: './test-output/vitest/coverage',
2635
+ provider: 'v8' as const,
2636
+ },
2637
+ passWithNoTests: true,
2638
+ },
2639
+ }));
2640
+ "
2641
+ `;
2642
+
2643
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > pnpm-workspace.yaml 1`] = `
2644
+ "packages:
2645
+ - 'packages/*'
2646
+ - 'test-app'
2647
+ - 'packages/common/*'
2648
+ - 'packages/common/constructs'
2649
+ "
2650
+ `;
2651
+
2652
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/README.md 1`] = `
2653
+ "# @proj/test-app
2654
+
2655
+ This library was generated with [@aws/nx-plugin](https://github.com/awslabs/nx-plugin-for-aws/).
2656
+
2657
+ ## Building
2658
+
2659
+ Run \`npx nx build @proj/test-app [--skip-nx-cache]\` to build the application.
2660
+
2661
+ ## Run dev server
2662
+
2663
+ Run \`npx nx serve @proj/test-app\`
2664
+
2665
+ ## Running unit tests
2666
+
2667
+ Run \`npx nx test @proj/test-app\` to execute the unit tests via Vitest.
2668
+
2669
+ ### Updating snapshots
2670
+
2671
+ To update snapshots, run the following command:
2672
+
2673
+ \`npx nx test @proj/test-app --configuration=update-snapshot\`
2674
+
2675
+ ## Run lint
2676
+
2677
+ Run \`npx nx lint @proj/test-app\`
2678
+
2679
+ ### Fixable issues
2680
+
2681
+ You can also automatically fix some lint errors by running the following command:
2682
+
2683
+ \`npx nx lint @proj/test-app --configuration=fix\`
2684
+
2685
+ ### Runtime config
2686
+
2687
+ In order to integrate with cognito or trpc backends, you need to have a \`runtime-config.json\` file in your \`/public\` website directory. You can fetch this is follows:
2688
+
2689
+ \`npx nx run @proj/test-app:load:runtime-config\`
2690
+
2691
+ > [!IMPORTANT]
2692
+ > Ensure you have AWS CLI and curl installed
2693
+ > You have deployed your CDK infrastructure into the appropriate account
2694
+ > You have assumed a role in the AWS account with sufficient permissions to call describe-stacks from cloudformation
2695
+
2696
+ ## Useful links
2697
+
2698
+ - [React website reference docs](TODO)
2699
+ - [Learn more about NX](https://nx.dev/getting-started/intro)
2700
+ "
2701
+ `;
2702
+
2703
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/eslint.config.mjs 1`] = `
2704
+ "import nx from '@nx/eslint-plugin';
2705
+ import baseConfig from '../eslint.config.mjs';
2706
+
2707
+ export default [
2708
+ ...baseConfig,
2709
+ ...nx.configs['flat/react'],
2710
+ {
2711
+ files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
2712
+ // Override or add rules here
2713
+ rules: {},
2714
+ },
2715
+ ];
2716
+ "
2717
+ `;
2718
+
2719
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/index.html 1`] = `
2720
+ "<!doctype html>
2721
+ <html lang="en">
2722
+ <head>
2723
+ <meta charset="utf-8" />
2724
+ <title>TestApp</title>
2725
+ <base href="/" />
2726
+
2727
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
2728
+ <link rel="icon" type="image/x-icon" href="/favicon.ico" />
2729
+ <link rel="stylesheet" href="/src/styles.css" />
2730
+ </head>
2731
+ <body>
2732
+ <div id="root"></div>
2733
+ <script type="module" src="/src/main.tsx"></script>
2734
+ </body>
2735
+ </html>
2736
+ "
2737
+ `;
2738
+
2739
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/project.json 1`] = `
2740
+ "{
2741
+ "name": "@proj/test-app",
2742
+ "$schema": "../node_modules/nx/schemas/project-schema.json",
2743
+ "sourceRoot": "test-app/src",
2744
+ "projectType": "application",
2745
+ "tags": [],
2746
+ "targets": {
2747
+ "build": {
2748
+ "dependsOn": ["lint", "compile", "bundle", "test"],
2749
+ "options": {
2750
+ "outputPath": "dist/test-app/bundle"
2751
+ }
2752
+ },
2753
+ "bundle": {
2754
+ "executor": "@nx/vite:build",
2755
+ "outputs": ["{options.outputPath}"],
2756
+ "defaultConfiguration": "production",
2757
+ "options": {
2758
+ "outputPath": "dist/test-app/bundle"
2759
+ },
2760
+ "configurations": {
2761
+ "development": {
2762
+ "mode": "development"
2763
+ },
2764
+ "production": {
2765
+ "mode": "production"
2766
+ }
2767
+ }
2768
+ },
2769
+ "compile": {
2770
+ "executor": "nx:run-commands",
2771
+ "outputs": ["{workspaceRoot}/dist/{projectRoot}/tsc"],
2772
+ "options": {
2773
+ "command": "tsc --build tsconfig.app.json",
2774
+ "cwd": "{projectRoot}"
2775
+ }
2776
+ },
2777
+ "lint": {
2778
+ "executor": "@nx/eslint:lint"
2779
+ },
2780
+ "load:runtime-config": {
2781
+ "executor": "nx:run-commands",
2782
+ "metadata": {
2783
+ "description": "Load runtime config from your deployed stack for dev purposes. You must set your AWS CLI credentials whilst calling 'pnpm exec nx run @proj/test-app:load:runtime-config'"
2784
+ },
2785
+ "options": {
2786
+ "command": "aws s3 cp s3://\`aws cloudformation describe-stacks --query \\"Stacks[?StackName=='proj-infra-sandbox'][].Outputs[?contains(OutputKey, 'WebsiteBucketName')].OutputValue\\" --output text\`/runtime-config.json './test-app/public/runtime-config.json'"
2787
+ }
2788
+ },
2789
+ "preview": {
2790
+ "dependsOn": ["build"],
2791
+ "executor": "@nx/vite:preview-server",
2792
+ "defaultConfiguration": "development",
2793
+ "options": {
2794
+ "buildTarget": "@proj/test-app:build"
2795
+ },
2796
+ "configurations": {
2797
+ "development": {
2798
+ "buildTarget": "@proj/test-app:build:development"
2799
+ },
2800
+ "production": {
2801
+ "buildTarget": "@proj/test-app:build:production"
2802
+ }
2803
+ }
2804
+ },
2805
+ "serve": {
2806
+ "executor": "@nx/vite:dev-server",
2807
+ "defaultConfiguration": "development",
2808
+ "options": {
2809
+ "buildTarget": "@proj/test-app:build"
2810
+ },
2811
+ "configurations": {
2812
+ "development": {
2813
+ "buildTarget": "@proj/test-app:build:development",
2814
+ "hmr": true
2815
+ },
2816
+ "production": {
2817
+ "buildTarget": "@proj/test-app:build:production",
2818
+ "hmr": false
2819
+ }
2820
+ }
2821
+ },
2822
+ "serve-local": {
2823
+ "executor": "@nx/vite:dev-server",
2824
+ "options": {
2825
+ "buildTarget": "@proj/test-app:build:development",
2826
+ "hmr": true,
2827
+ "mode": "serve-local"
2828
+ },
2829
+ "continuous": true
2830
+ },
2831
+ "serve-static": {
2832
+ "executor": "@nx/web:file-server",
2833
+ "dependsOn": ["build"],
2834
+ "options": {
2835
+ "buildTarget": "@proj/test-app:build",
2836
+ "spa": true
2837
+ }
2838
+ },
2839
+ "test": {
2840
+ "executor": "@nx/vite:test",
2841
+ "outputs": ["{options.reportsDirectory}"],
2842
+ "options": {
2843
+ "reportsDirectory": "../coverage/test-app"
2844
+ }
2845
+ }
2846
+ },
2847
+ "metadata": {
2848
+ "generator": "ts#react-website"
2849
+ }
2850
+ }
2851
+ "
2852
+ `;
2853
+
2854
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/public/favicon.ico 1`] = `
2855
+ "00 �%6  ��% h�6(0\` $V/V/cV/�V/�V/�V/�V/�W0�Y1'B#pH[�f��i��i��i��i��i��ia�j�c�^R�\\��Y��U��R�|N�xKuI&V/
2856
+ V/�V/�V/�V/�V/�V/�X1�Y2Ld=9_;�X��l��k��k��k��k��k�kH�c8�a�]��Z��W��S�}P�zM�vIV/
2857
+ V/�V/�V/�V/�V/�W0�Y1�Z3LoD jA�\`;�_=��c��l��k��k��k��k��kÞk�j�f��c��\`��]��Y��V��R�}OCV/
2858
+ V/�V/�V/�V/�V/�W0�Z2�[3LoD[nD�iA�X7�oI��j��k��k��k��k��k��k��m�ks�i��f��b��_��[��W��T�yLV/
2859
+ V/�V/�V/�V/�V/�X1�Z3�\\4MnDoE�qF�oE�f@�X8��Z��l��k��k��k��k��k�ks�k��k��h��d��a��]��Y˅WV/
2860
+ V/�V/�V/�V/�V/�Y1�[3�\\4Ph=nD�pE�rG�sH�oF�a=�cA��f��k��k��k��k��k��k��k��k��j��f��b��_�\\SV/
2861
+ V/�V/�V/�V/�W0�Y2�[4�]5QmC6oD�qF�sH�uJ�uJ�nF�];�wO��k��k��k��k��k��k��k��k��k��h��d��\`��\\V/
2862
+ V/V/
2863
+ V/�V/�V/�V/�W0�Y2�\\4�]5QkA
2864
+ mC�oD�qF�tH�vJ�xL�vK�kD�^=��_��l��k��k��k��k��k��k��k��i��eؔb(V/ V/�V/eV/
2865
+ V/�V/�V/�V/�W0�Z2�\\4�^6QlAXmC�oE�rG�tI�wK�yM�zN�uK�eA�jF��h��k��k��k��k��k��k��k��j��geW0V/RV/�V/
2866
+ V/�V/�V/�V/�W0�Z2�\\4�^6Qj@kA�mC�pE�rG�uI�wK�yM�|O�{O�rJ�^=�|S��k��k��k��k��k��k��k��j��h �Z]5iY1�V/GV/
2867
+ V/�V/�V/�V/�X0�Z2�\\5�^6Qi?kA�mC�pE�rG�uI�wK�zM�|O�}P�xN�eB�W:��c��k��k��k��k��k��o���$W��H��H��KHɦ9�f>�X1�V/�V/
2868
+ V/�V/�V/�V/�X0�Z2�\\4�^6Qg>4i?�kA�mC�pE�rG�uI�wK�zM�|O�|P�vM�b@�bA��g��k��k��k��k��k��s �ӵ]������H-��H���J���G���*�\`8�Y1�V/�V/
2869
+ V/�V/�V/�V/�W0�Z2�\\4�^6Qd; f=�h?�kA�mC�pE�rG�tI�wK�yM�{O�yN�mF�^>��]��l��k��k��k��k��k��l�ͫH��ڔ��ٛ�ؖ�ؖ�ؖ.�ؘr�֏���O�߾D���/��h�i@�]5�Y1�V/�V/
2870
+ V/�V/�V/�V/�W0�Z2�\\4�^5Qd;Uf<�h>�j@�mC�oE�rG�tH�wK�yL�xM�qI�_=�vO��k��k��k��k��k��k��k��j������i��א��ؗ��ؘ��ؗ��֏���k���G��w�mC�e;�a8�]5�X1�V/]V/
2871
+ V/�V/�V/�V/�W0�Y2�\\4�]5Pb:c:�e<�h>�j@�lB�oD�qF�rGDwK}wK�sI�d@�cA��f��k��k��k��k��k��k��k��k��i���$���W���p���v���n���Y���I���*�rG�j@�f<�a8�\\4�X1�V/ V/
2872
+ V/�V/�V/�V/�W0�Y1�[3�\\5Qa8wb:�e<�g>�i@�lB�nD�pE�oCuI}sH�iB�Z:��Z��l��k��k��k��k��k��k��k��j��f��e����Ω4�ܹA�޼B�״=���(�}R�nC�j@�e<�\`8�[4�X1�V/
2873
+ V/�V/�V/�V/�V/�X1�[3�]5�\`7�b9�d;�f=�i?�kA�mC�oD*qG}kD�Z9�oI��j��k��k��k��k��k��k�k��k��i��e��a��]��_��g ��g
2874
+ ��[�xK�rF�nC�i?�d;�_7�[3�X1V/
2875
+ V/�V/�V/�V/�V/�X0�Z2�\\4�_6�a8�c:�f<�h>�j@�lBqjB}_<�\\;��c��l��k��k��k��k��k۞kC�k��j��g��c��\`��\\��X��S�}O�yL�uI�qE�lA�g>�c:�^6�[3JV/
2876
+ V/�V/�V/�V/�V/�W0�Y2�\\4�^6�\`8�b:�e;�g=�i?�kA\`;}U6�U��l��k��k��k��k��k��kl�k$�h��d��a��^��Z��V��S�}O�xK�tH�oD�j@�f<�a9�^6ZS,V/
2877
+ V/�V/�V/�V/�V/�V/�X1�[3�]5�_7�a9�d;�f<�g>MT4~kE��i��k��k��k��k��k��k��k�e�b��_�[��X��T�Q�zM�vJ�rF�mB�i?�e;�a8BW0V/
2878
+ V/�V/�V/�V/�V/�V/�W0�Z2�\\4�^6�\`8�b:�d;�g=iC~�a��k��k��k��k��k��k�k:�\`�]@�Y��VڀR�|O�xK�tH�pD�lA�h>he;V/
2879
+ V/�V/�V/�V/�V/�V/�W0�Y1�[3�]5�_7�a8�c:.xL~Q��R��S��T��T��U��W��o�W�TQ={MTwJYsGJoD+kA V/
2880
+ V/�V/�V/�V/�V/�V/�V/�X0�Z2�\\4�^6�\`7wkA}lB�nC�oD�pF�rG�sH�sH�V/
2881
+ V/�V/�V/�V/�V/�V/�V/�W/�X1�Z3�\\4�^6j@}kA�lB�nC�oD�pE�qF�rG�V/
2882
+ V/�V/�V/�V/�V/�V/�V/�V/�W0�Y2�[3Rh>}i?�j@�lB�mC�nC�oD�pE�V/
2883
+ V/�V/�V/�V/�V/�V/�V/�V/�V/�W0�Z2f=}g=�h?�j@�kA�lB�mB�mC�V/
2884
+ V/�V/�V/�V/�V/�V/�V/�V/�V/�V/2d;}e<�f=�g>�i?�j@�j@�kA�V/
2885
+ V/�V/�V/�V/�V/�V/�V/�V/�V/~b9}c:�d;�e<�f=�g>�h>�i?�V/
2886
+ V/�V/�V/�V/�V/�V/�V/�V/�V/\`7}a8�b9�c:�d;�e<�f<�f=�V/V/TV/pV/nV/nV/nV/nV/oV/:_66\`7oa8nb9nc:nd;nd;pe;C�������������������������������������������������������������������������>�������� ������������?����������������>����\`��\`����������?���?����?����?����?����?���?�?����?����?��������������������������������������������������( @ V/V/XV/\\V/\\V/]X1/L,~SI�i\`�i_�i_�i[�i�_�\\V�X\\�S\\{N^wJ,V/KV/�V/�V/�W0�Y1�d=BgA�b��k��k��k��k��k�s�c��_��Z��U�}P�xL6V/KV/�V/�V/�X1�Z3�pEmC�b=�pJ��j��k��k��k�kJ�kA�g�c��]��X��TyV/KV/�V/�V/�Y1�[3�oDfqF�nE�\`=��Y��l��k��k��kϞk˝j��f��\`��[��VV/KV/�V/�W/�Z2�\\4�mC#oD�rG�uI�lE�hD��e��k��k��k��k��k��h��c�^FV/V/ V/KV/�V/�W0�Z3�]5�h>mC�pE�sH�wK�wL�hC�yP��k��k��k��k��k��i��e��[V/*V/zV/KV/�V/�W0�[3�]5�kA@mB�pE�tI�xL�{N�wL�fC��]��l��k��k��k��j͚g�w ]5\\W0oV/KV/�V/�W0�[3�]5�g>j@�mB�qF�tI�xL�|O�|P�hC�mI��k��k��k��l������F��J ��NIĢ6�d<�V/�V/KV/�V/�W0�[3�]5�g=ci?�mB�pE�tH�xL�{N�wM�eB��[��k��k��k��j���3��ڑU�ݩ�ڜ�ٜF��uk߾Dҽ�1��c�]5�W0�V/KV/�V/�W0�Z3�]5�d;e<�i?�lB�pE�sH�wK�wL�hC�vN��j��k��k��k��j��z�ܿ^��ֈ��׍��Ԃ���Z���!�mC�a8�[4�W0�V/KV/�V/�W/�Z2�\\4�b9�d;�h>�kA�oD�qFBuJ�mE�fB��d��k��k��k��k��k��g��{�Ϊ=�ܽM�ٸD���'�uJ�h>�b9�[3�W06V/KV/�V/�V/�Y1�\\4�\`8�c:�g=�j@�mC�zKlD�_<��W��l��k��k��k��k؝j��f��_��_��e
2887
+ ��] �wK�nC�g=�\`7�[3L'V/KV/�V/�V/�X1�[3�_6�b9�e<�h?�kA%\\9�mG��i��k��k��k��ke�k9�gՔb��]��W�Q�yL�sG�lA�e<�\`7�[3V/KV/�V/�V/�W0�Z2�]5�a8�d;�f=jeA��a��l��l��k��k��k �d.�_��Z�U�}O�vJ�pE�j?�d;v_7V/KV/�V/�V/�V/�X1�\\4�_7�b9�e;|P��Y��Z��[��\\�aA�\\�W7�RnzM�tH�nC\\i?!a9V/KV/�V/�V/�V/�W0�Z2�]5�_7Gj?lA�mC�oD�qF�sG�sH+V/KV/�V/�V/�V/�V/�X1�[3�\`7b8i?�j@�mB�nD�pE�pE+V/KV/�V/�V/�V/�V/�V/�X1)_6f=�g>�i@�kA�lB�mC+V/LV/�V/�V/�V/�V/�V/q]4c:�d;�f=�h>�i?�i?+V/@V/�V/�V/�V/�V/�V/[2\`8�b9�c:�e;�f<�f=$V/V/V/V/V/V/_6\`7a9c:d;d;����������������������������������0��0���������������������00�p8�p?�����������������������������������(  V/'V/;W0*Z3^:�]2�k=�j%�]#�V<{N(j?V/�V/�X1�\\4h@LvM�i��kʞkA�cƉY�QaV/�V/�Z2�[4nCqF�lE��Z��l��k�h��\`��VV/ V/�W0�[3�[4mCrrG�wK�tL��e��k��j�d8��(
2888
+ \\5VV/�W0�[3�f=1kA�rG�zM�qI��^��k��z���z0��#��R^�}#�b:�V/�W0�Z3�d;�j@�qF�qH�zP��j��k��r�ƤB�ڽ]㫆*�lC�[3�V/�V/�Z2�a8�g>�jAGlF“c��l��k��e�a��^�sH�c:�[47V/�V/�X1�^6�c:�^:�TŒa��d��n
2889
+ �\`@�V�xK�mB�d;-V/�V/�V/�Z2�_6 mB
2890
+ mC�pE�sG�yLtHlAV/�V/�V/�W/dc: e<�h?�j@�V/RV/|V/hV/_7a9^d;}f<A��������Oc ������"
2891
+ `;
2892
+
2893
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/src/components/AppLayout/index.tsx 1`] = `
2894
+ "import * as React from 'react';
2895
+ import { createContext, useCallback, useEffect, useState } from 'react';
2896
+ import Config from '../../config';
2897
+
2898
+ import {
2899
+ BreadcrumbGroup,
2900
+ BreadcrumbGroupProps,
2901
+ SideNavigation,
2902
+ TopNavigation,
2903
+ } from '@cloudscape-design/components';
2904
+ import CloudscapeAppLayout, {
2905
+ AppLayoutProps,
2906
+ } from '@cloudscape-design/components/app-layout';
2907
+ import { matchByPath, useLocation, useNavigate } from '@tanstack/react-router';
2908
+
2909
+ const getBreadcrumbs = (
2910
+ pathName: string,
2911
+ search: string,
2912
+ defaultBreadcrumb: string,
2913
+ availableRoutes?: string[],
2914
+ ) => {
2915
+ const segments = [
2916
+ defaultBreadcrumb,
2917
+ ...pathName.split('/').filter((segment) => segment !== ''),
2918
+ ];
2919
+
2920
+ return segments.map((segment, i) => {
2921
+ const href =
2922
+ i === 0
2923
+ ? '/'
2924
+ : \`/\${segments
2925
+ .slice(1, i + 1)
2926
+ .join('/')
2927
+ .replace('//', '/')}\`;
2928
+
2929
+ const matched =
2930
+ !availableRoutes || availableRoutes.find((r) => matchByPath(r, href, {}));
2931
+
2932
+ return {
2933
+ href: matched ? \`\${href}\${search}\` : '#',
2934
+ text: segment,
2935
+ };
2936
+ });
2937
+ };
2938
+
2939
+ export interface AppLayoutContext {
2940
+ appLayoutProps: AppLayoutProps;
2941
+ setAppLayoutProps: (props: AppLayoutProps) => void;
2942
+ displayHelpPanel: (helpContent: React.ReactNode) => void;
2943
+ }
2944
+
2945
+ /**
2946
+ * Context for updating/retrieving the AppLayout.
2947
+ */
2948
+ export const AppLayoutContext = createContext({
2949
+ appLayoutProps: {},
2950
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
2951
+ setAppLayoutProps: (_: AppLayoutProps) => {},
2952
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
2953
+ displayHelpPanel: (_: React.ReactNode) => {},
2954
+ });
2955
+
2956
+ /**
2957
+ * Defines the App layout and contains logic for routing.
2958
+ */
2959
+ const AppLayout: React.FC<React.PropsWithChildren> = ({ children }) => {
2960
+ const appLayout = React.useRef<AppLayoutProps.Ref>(null);
2961
+ const [appLayoutProps, setAppLayoutProps] = useState<AppLayoutProps>({});
2962
+ const setAppLayoutPropsSafe = useCallback(
2963
+ (props: AppLayoutProps) => {
2964
+ JSON.stringify(appLayoutProps) !== JSON.stringify(props) &&
2965
+ setAppLayoutProps(props);
2966
+ },
2967
+ [appLayoutProps],
2968
+ );
2969
+
2970
+ const navigate = useNavigate();
2971
+ const [activeBreadcrumbs, setActiveBreadcrumbs] = useState<
2972
+ BreadcrumbGroupProps.Item[]
2973
+ >([{ text: '/', href: '/' }]);
2974
+ const { pathname, search } = useLocation();
2975
+
2976
+ useEffect(() => {
2977
+ const breadcrumbs = getBreadcrumbs(
2978
+ pathname,
2979
+ Object.entries(search).reduce((p, [k, v]) => p + \`\${k}=\${v}\`, ''),
2980
+ '/',
2981
+ );
2982
+ setActiveBreadcrumbs(breadcrumbs);
2983
+ }, [pathname, search]);
2984
+
2985
+ const onNavigate = useCallback(
2986
+ (e: CustomEvent<{ href: string; external?: boolean }>) => {
2987
+ if (!e.detail.external) {
2988
+ e.preventDefault();
2989
+ setAppLayoutPropsSafe({
2990
+ contentType: undefined,
2991
+ });
2992
+ navigate({ to: e.detail.href });
2993
+ }
2994
+ },
2995
+ [navigate, setAppLayoutPropsSafe],
2996
+ );
2997
+
2998
+ return (
2999
+ <AppLayoutContext.Provider
3000
+ value={{
3001
+ appLayoutProps,
3002
+ setAppLayoutProps: setAppLayoutPropsSafe,
3003
+ displayHelpPanel: (helpContent: React.ReactNode) => {
3004
+ setAppLayoutPropsSafe({ tools: helpContent, toolsHide: false });
3005
+ appLayout.current?.openTools();
3006
+ },
3007
+ }}
3008
+ >
3009
+ <TopNavigation
3010
+ identity={{
3011
+ href: '/',
3012
+ title: Config.applicationName,
3013
+ logo: {
3014
+ src: Config.logo,
3015
+ },
3016
+ }}
3017
+ />
3018
+ <CloudscapeAppLayout
3019
+ ref={appLayout}
3020
+ breadcrumbs={
3021
+ <BreadcrumbGroup onFollow={onNavigate} items={activeBreadcrumbs} />
3022
+ }
3023
+ navigation={
3024
+ <SideNavigation
3025
+ header={{ text: Config.applicationName, href: '/' }}
3026
+ activeHref={pathname}
3027
+ onFollow={onNavigate}
3028
+ items={[{ text: 'Home', type: 'link', href: '/' }]}
3029
+ />
3030
+ }
3031
+ toolsHide
3032
+ content={children}
3033
+ {...appLayoutProps}
3034
+ />
3035
+ </AppLayoutContext.Provider>
3036
+ );
3037
+ };
3038
+
3039
+ export default AppLayout;
3040
+ "
3041
+ `;
3042
+
3043
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/src/config.ts 1`] = `
3044
+ "export default {
3045
+ applicationName: 'test-app',
3046
+ logo: 'data:image/svg+xml;base64,PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KDTwhLS0gVXBsb2FkZWQgdG86IFNWRyBSZXBvLCB3d3cuc3ZncmVwby5jb20sIFRyYW5zZm9ybWVkIGJ5OiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4KPHN2ZyBmaWxsPSIjMjQ4YmFlIiB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0cm9rZT0iIzI0OGJhZSI+Cg08ZyBpZD0iU1ZHUmVwb19iZ0NhcnJpZXIiIHN0cm9rZS13aWR0aD0iMCIvPgoNPGcgaWQ9IlNWR1JlcG9fdHJhY2VyQ2FycmllciIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cg08ZyBpZD0iU1ZHUmVwb19pY29uQ2FycmllciI+Cg08dGl0bGU+aW9uaWNvbnMtdjVfbG9nb3M8L3RpdGxlPgoNPHBhdGggZD0iTTQxMC42NiwxODAuNzJoMHEtNy42Ny0yLjYyLTE1LjQ1LTQuODgsMS4yOS01LjI1LDIuMzgtMTAuNTZjMTEuNy01Ni45LDQuMDUtMTAyLjc0LTIyLjA2LTExNy44My0yNS0xNC40OC02NiwuNjEtMTA3LjM2LDM2LjY5cS02LjEsNS4zNC0xMS45NSwxMS0zLjktMy43Ni04LTcuMzZjLTQzLjM1LTM4LjU4LTg2LjgtNTQuODMtMTEyLjg4LTM5LjY5LTI1LDE0LjUxLTMyLjQzLDU3LjYtMjEuOSwxMTEuNTNxMS41OCw4LDMuNTUsMTUuOTNjLTYuMTUsMS43NS0xMi4wOSwzLjYyLTE3Ljc3LDUuNkM0OC40NiwxOTguOSwxNiwyMjYuNzMsMTYsMjU1LjU5YzAsMjkuODIsMzQuODQsNTkuNzIsODcuNzcsNzcuODVxNi40NCwyLjE5LDEzLDQuMDdRMTE0LjY0LDM0NiwxMTMsMzU0LjY4Yy0xMCw1My0yLjIsOTUuMDcsMjIuNzUsMTA5LjQ5LDI1Ljc3LDE0Ljg5LDY5LS40MSwxMTEuMTQtMzcuMzFxNS00LjM4LDEwLTkuMjUsNi4zMiw2LjExLDEzLDExLjg2YzQwLjgsMzUuMTgsODEuMDksNDkuMzksMTA2LDM0LjkzLDI1Ljc1LTE0Ljk0LDM0LjEyLTYwLjE0LDIzLjI1LTExNS4xM3EtMS4yNS02LjMtMi44OC0xMi44Niw0LjU2LTEuMzUsOC45My0yLjc5YzU1LTE4LjI3LDkwLjgzLTQ3LjgxLDkwLjgzLTc4QzQ5NiwyMjYuNjIsNDYyLjUsMTk4LjYxLDQxMC42NiwxODAuNzJabS0xMjktODEuMDhjMzUuNDMtMzAuOTEsNjguNTUtNDMuMTEsODMuNjUtMzQuMzloMGMxNi4wNyw5LjI5LDIyLjMyLDQ2Ljc1LDEyLjIyLDk1Ljg4cS0xLDQuOC0yLjE2LDkuNTdhNDg3LjgzLDQ4Ny44MywwLDAsMC02NC4xOC0xMC4xNiw0ODEuMjcsNDgxLjI3LDAsMCwwLTQwLjU3LTUwLjc1UTI3NiwxMDQuNTcsMjgxLjY0LDk5LjY0Wk0xNTcuNzMsMjgwLjI1cTYuNTEsMTIuNiwxMy42MSwyNC44OSw3LjIzLDEyLjU0LDE1LjA3LDI0LjcxYTQzNS4yOCw0MzUuMjgsMCwwLDEtNDQuMjQtNy4xM0MxNDYuNDEsMzA5LDE1MS42MywyOTQuNzUsMTU3LjczLDI4MC4yNVptMC00OC4zM2MtNi0xNC4xOS0xMS4wOC0yOC4xNS0xNS4yNS00MS42MywxMy43LTMuMDcsMjguMy01LjU4LDQzLjUyLTcuNDhxLTcuNjUsMTEuOTQtMTQuNzIsMjQuMjNUMTU3LjcsMjMxLjkyWm0xMC45LDI0LjE3cTkuNDgtMTkuNzcsMjAuNDItMzguNzhoMHExMC45My0xOSwyMy4yNy0zNy4xM2MxNC4yOC0xLjA4LDI4LjkyLTEuNjUsNDMuNzEtMS42NXMyOS41Mi41Nyw0My43OSwxLjY2cTEyLjIxLDE4LjA5LDIzLjEzLDM3dDIwLjY5LDM4LjZRMzM0LDI3NS42MywzMjMsMjk0LjczaDBxLTEwLjkxLDE5LTIzLDM3LjI0Yy0xNC4yNSwxLTI5LDEuNTUtNDQsMS41NXMtMjkuNDctLjQ3LTQzLjQ2LTEuMzhxLTEyLjQzLTE4LjE5LTIzLjQ2LTM3LjI5VDE2OC42LDI1Ni4wOVpNMzQwLjc1LDMwNXE3LjI1LTEyLjU4LDEzLjkyLTI1LjQ5aDBhNDQwLjQxLDQ0MC40MSwwLDAsMSwxNi4xMiw0Mi4zMkE0MzQuNDQsNDM0LjQ0LDAsMCwxLDMyNiwzMjkuNDhRMzMzLjYyLDMxNy4zOSwzNDAuNzUsMzA1Wm0xMy43Mi03My4wN3EtNi42NC0xMi42NS0xMy44MS0yNWgwcS03LTEyLjE4LTE0LjU5LTI0LjA2YzE1LjMxLDEuOTQsMzAsNC41Miw0My43Nyw3LjY3QTQzOS44OSw0MzkuODksMCwwLDEsMzU0LjQ3LDIzMS45M1pNMjU2LjIzLDEyNC40OGgwYTQzOS43NSw0MzkuNzUsMCwwLDEsMjguMjUsMzQuMThxLTI4LjM1LTEuMzUtNTYuNzQsMEMyMzcuMDcsMTQ2LjMyLDI0Ni42MiwxMzQuODcsMjU2LjIzLDEyNC40OFpNMTQ1LjY2LDY1Ljg2YzE2LjA2LTkuMzIsNTEuNTcsNCw4OSwzNy4yNywyLjM5LDIuMTMsNC44LDQuMzYsNy4yLDYuNjdBNDkxLjM3LDQ5MS4zNywwLDAsMCwyMDEsMTYwLjUxYTQ5OS4xMiw0OTkuMTIsMCwwLDAtNjQuMDYsMTBxLTEuODMtNy4zNi0zLjMtMTQuODJoMEMxMjQuNTksMTA5LjQ2LDEzMC41OCw3NC42MSwxNDUuNjYsNjUuODZaTTEyMi4yNSwzMTcuNzFxLTYtMS43MS0xMS44NS0zLjcxYy0yMy40LTgtNDIuNzMtMTguNDQtNTYtMjkuODFDNDIuNTIsMjc0LDM2LjUsMjYzLjgzLDM2LjUsMjU1LjU5YzAtMTcuNTEsMjYuMDYtMzkuODUsNjkuNTItNTVxOC4xOS0yLjg1LDE2LjUyLTUuMjFhNDkzLjU0LDQ5My41NCwwLDAsMCwyMy40LDYwLjc1QTUwMi40Niw1MDIuNDYsMCwwLDAsMTIyLjI1LDMxNy43MVptMTExLjEzLDkzLjY3Yy0xOC42MywxNi4zMi0zNy4yOSwyNy44OS01My43NCwzMy43MmgwYy0xNC43OCw1LjIzLTI2LjU1LDUuMzgtMzMuNjYsMS4yNy0xNS4xNC04Ljc1LTIxLjQ0LTQyLjU0LTEyLjg1LTg3Ljg2cTEuNTMtOCwzLjUtMTZhNDgwLjg1LDQ4MC44NSwwLDAsMCw2NC42OSw5LjM5LDUwMS4yLDUwMS4yLDAsMCwwLDQxLjIsNTFDMjM5LjU0LDQwNS44MywyMzYuNDksNDA4LjY1LDIzMy4zOCw0MTEuMzhabTIzLjQyLTIzLjIyYy05LjcyLTEwLjUxLTE5LjQyLTIyLjE0LTI4Ljg4LTM0LjY0cTEzLjc5LjU0LDI4LjA4LjU0YzkuNzgsMCwxOS40Ni0uMjEsMjktLjY0QTQzOS4zMyw0MzkuMzMsMCwwLDEsMjU2LjgsMzg4LjE2Wm0xMjQuNTIsMjguNTljLTIuODYsMTUuNDQtOC42MSwyNS43NC0xNS43MiwyOS44Ni0xNS4xMyw4Ljc4LTQ3LjQ4LTIuNjMtODIuMzYtMzIuNzItNC0zLjQ0LTgtNy4xMy0xMi4wNy0xMWE0ODQuNTQsNDg0LjU0LDAsMCwwLDQwLjIzLTUxLjIsNDc3Ljg0LDQ3Ny44NCwwLDAsMCw2NS0xMC4wNXExLjQ3LDUuOTQsMi42LDExLjY0aDBDMzgzLjgxLDM3Ny41OCwzODQuNSwzOTkuNTYsMzgxLjMyLDQxNi43NVptMTcuNC0xMDIuNjRoMGMtMi42Mi44Ny01LjMyLDEuNzEtOC4wNiwyLjUzYTQ4My4yNiw0ODMuMjYsMCwwLDAtMjQuMzEtNjAuOTQsNDgxLjUyLDQ4MS41MiwwLDAsMCwyMy4zNi02MC4wNmM0LjkxLDEuNDMsOS42OCwyLjkzLDE0LjI3LDQuNTIsNDQuNDIsMTUuMzIsNzEuNTIsMzgsNzEuNTIsNTUuNDNDNDc1LjUsMjc0LjE5LDQ0Ni4yMywyOTguMzMsMzk4LjcyLDMxNC4xMVoiLz4KDTxwYXRoIGQ9Ik0yNTYsMjk4LjU1YTQzLDQzLDAsMSwwLTQyLjg2LTQzQTQyLjkxLDQyLjkxLDAsMCwwLDI1NiwyOTguNTVaIi8+Cg08L2c+Cg08L3N2Zz4=',
3047
+ };
3048
+ "
3049
+ `;
3050
+
3051
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/src/hooks/useAppLayout.tsx 1`] = `
3052
+ "import { useContext } from 'react';
3053
+ import { AppLayoutContext } from '../components/AppLayout';
3054
+
3055
+ export const useAppLayout = (): AppLayoutContext =>
3056
+ useContext(AppLayoutContext);
3057
+ "
3058
+ `;
3059
+
3060
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/src/main.tsx 1`] = `
3061
+ "import React from 'react';
3062
+ import { createRoot } from 'react-dom/client';
3063
+ import { I18nProvider } from '@cloudscape-design/components/i18n';
3064
+ import messages from '@cloudscape-design/components/i18n/messages/all.en';
3065
+ import '@cloudscape-design/global-styles/index.css';
3066
+ import { RouterProvider, createRouter } from '@tanstack/react-router';
3067
+ import { routeTree } from './routeTree.gen';
3068
+
3069
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
3070
+ export type RouterProviderContext = {};
3071
+
3072
+ const router = createRouter({
3073
+ routeTree,
3074
+ context: {},
3075
+ });
3076
+
3077
+ // Register the router instance for type safety
3078
+ declare module '@tanstack/react-router' {
3079
+ interface Register {
3080
+ router: typeof router;
3081
+ }
3082
+ }
3083
+
3084
+ const App = () => {
3085
+ return <RouterProvider router={router} context={{}} />;
3086
+ };
3087
+
3088
+ const root = document.getElementById('root');
3089
+ root &&
3090
+ createRoot(root).render(
3091
+ <React.StrictMode>
3092
+ <I18nProvider locale="en" messages={[messages]}>
3093
+ <App />
3094
+ </I18nProvider>
3095
+ </React.StrictMode>,
3096
+ );
3097
+ "
3098
+ `;
3099
+
3100
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/src/routeTree.gen.ts 1`] = `
3101
+ "/* eslint-disable */
3102
+
3103
+ // @ts-nocheck
3104
+
3105
+ // noinspection JSUnusedGlobalSymbols
3106
+
3107
+ // This file was automatically generated by TanStack Router.
3108
+ // You should NOT make any changes in this file as it will be overwritten.
3109
+ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
3110
+
3111
+ // Import Routes
3112
+
3113
+ import { Route as rootRoute } from './routes/__root';
3114
+ import { Route as IndexImport } from './routes/index';
3115
+ import { Route as WelcomeIndexImport } from './routes/welcome/index';
3116
+
3117
+ // Create/Update Routes
3118
+
3119
+ const IndexRoute = IndexImport.update({
3120
+ id: '/',
3121
+ path: '/',
3122
+ getParentRoute: () => rootRoute,
3123
+ } as any);
3124
+
3125
+ const WelcomeIndexRoute = WelcomeIndexImport.update({
3126
+ id: '/welcome/',
3127
+ path: '/welcome/',
3128
+ getParentRoute: () => rootRoute,
3129
+ } as any);
3130
+
3131
+ // Populate the FileRoutesByPath interface
3132
+
3133
+ declare module '@tanstack/react-router' {
3134
+ interface FileRoutesByPath {
3135
+ '/': {
3136
+ id: '/';
3137
+ path: '/';
3138
+ fullPath: '/';
3139
+ preLoaderRoute: typeof IndexImport;
3140
+ parentRoute: typeof rootRoute;
3141
+ };
3142
+ '/welcome/': {
3143
+ id: '/welcome/';
3144
+ path: '/welcome';
3145
+ fullPath: '/welcome';
3146
+ preLoaderRoute: typeof WelcomeIndexImport;
3147
+ parentRoute: typeof rootRoute;
3148
+ };
3149
+ }
3150
+ }
3151
+
3152
+ // Create and export the route tree
3153
+
3154
+ export interface FileRoutesByFullPath {
3155
+ '/': typeof IndexRoute;
3156
+ '/welcome': typeof WelcomeIndexRoute;
3157
+ }
3158
+
3159
+ export interface FileRoutesByTo {
3160
+ '/': typeof IndexRoute;
3161
+ '/welcome': typeof WelcomeIndexRoute;
3162
+ }
3163
+
3164
+ export interface FileRoutesById {
3165
+ __root__: typeof rootRoute;
3166
+ '/': typeof IndexRoute;
3167
+ '/welcome/': typeof WelcomeIndexRoute;
3168
+ }
3169
+
3170
+ export interface FileRouteTypes {
3171
+ fileRoutesByFullPath: FileRoutesByFullPath;
3172
+ fullPaths: '/' | '/welcome';
3173
+ fileRoutesByTo: FileRoutesByTo;
3174
+ to: '/' | '/welcome';
3175
+ id: '__root__' | '/' | '/welcome/';
3176
+ fileRoutesById: FileRoutesById;
3177
+ }
3178
+
3179
+ export interface RootRouteChildren {
3180
+ IndexRoute: typeof IndexRoute;
3181
+ WelcomeIndexRoute: typeof WelcomeIndexRoute;
3182
+ }
3183
+
3184
+ const rootRouteChildren: RootRouteChildren = {
3185
+ IndexRoute: IndexRoute,
3186
+ WelcomeIndexRoute: WelcomeIndexRoute,
3187
+ };
3188
+
3189
+ export const routeTree = rootRoute
3190
+ ._addFileChildren(rootRouteChildren)
3191
+ ._addFileTypes<FileRouteTypes>();
3192
+
3193
+ /* ROUTE_MANIFEST_START
3194
+ {
3195
+ "routes": {
3196
+ "__root__": {
3197
+ "filePath": "__root.tsx",
3198
+ "children": [
3199
+ "/",
3200
+ "/welcome/"
3201
+ ]
3202
+ },
3203
+ "/": {
3204
+ "filePath": "index.tsx"
3205
+ },
3206
+ "/welcome/": {
3207
+ "filePath": "welcome/index.tsx"
3208
+ }
3209
+ }
3210
+ }
3211
+ ROUTE_MANIFEST_END */
3212
+ "
3213
+ `;
3214
+
3215
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/src/routes/__root.tsx 1`] = `
3216
+ "import { createRootRouteWithContext } from '@tanstack/react-router';
3217
+ import AppLayout from '../components/AppLayout';
3218
+ import { RouterProviderContext } from '../main';
3219
+ import { Outlet } from '@tanstack/react-router';
3220
+
3221
+ export const Route = createRootRouteWithContext<RouterProviderContext>()({
3222
+ component: () => (
3223
+ <AppLayout>
3224
+ <Outlet />
3225
+ </AppLayout>
3226
+ ),
3227
+ });
3228
+ "
3229
+ `;
3230
+
3231
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/src/routes/index.tsx 1`] = `
3232
+ "import {
3233
+ ContentLayout,
3234
+ Header,
3235
+ SpaceBetween,
3236
+ Container,
3237
+ } from '@cloudscape-design/components';
3238
+ import { createFileRoute } from '@tanstack/react-router';
3239
+
3240
+ export const Route = createFileRoute('/')({
3241
+ component: RouteComponent,
3242
+ });
3243
+
3244
+ function RouteComponent() {
3245
+ return (
3246
+ <ContentLayout header={<Header>Welcome</Header>}>
3247
+ <SpaceBetween size="l">
3248
+ <Container>Welcome to your new React website!</Container>
3249
+ </SpaceBetween>
3250
+ </ContentLayout>
3251
+ );
3252
+ }
3253
+ "
3254
+ `;
3255
+
3256
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/src/styles.css 1`] = `
3257
+ "@import 'tailwindcss';
3258
+ /* You can add global styles to this file, and also import other style files */
3259
+ "
3260
+ `;
3261
+
3262
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/tsconfig.app.json 1`] = `
3263
+ "{
3264
+ "extends": "../tsconfig.base.json",
3265
+ "compilerOptions": {
3266
+ "outDir": "../dist/test-app/tsc",
3267
+ "tsBuildInfoFile": "../dist/test-app/tsc/tsconfig.lib.tsbuildinfo",
3268
+ "jsx": "react-jsx",
3269
+ "lib": ["DOM"],
3270
+ "types": [
3271
+ "node",
3272
+ "@nx/react/typings/cssmodule.d.ts",
3273
+ "@nx/react/typings/image.d.ts",
3274
+ "vite/client"
3275
+ ]
3276
+ },
3277
+ "exclude": [
3278
+ "src/**/*.spec.ts",
3279
+ "src/**/*.test.ts",
3280
+ "src/**/*.spec.tsx",
3281
+ "src/**/*.test.tsx",
3282
+ "src/**/*.spec.js",
3283
+ "src/**/*.test.js",
3284
+ "src/**/*.spec.jsx",
3285
+ "src/**/*.test.jsx",
3286
+ "vite.config.ts",
3287
+ "vite.config.mts",
3288
+ "vitest.config.ts",
3289
+ "vitest.config.mts"
3290
+ ],
3291
+ "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
3292
+ }
3293
+ "
3294
+ `;
3295
+
3296
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/tsconfig.json 1`] = `
3297
+ "{
3298
+ "files": [],
3299
+ "include": [],
3300
+ "references": [
3301
+ {
3302
+ "path": "./tsconfig.app.json"
3303
+ },
3304
+ {
3305
+ "path": "./tsconfig.spec.json"
3306
+ }
3307
+ ],
3308
+ "extends": "../tsconfig.base.json",
3309
+ "compilerOptions": {
3310
+ "moduleResolution": "Bundler",
3311
+ "module": "Preserve"
3312
+ }
3313
+ }
3314
+ "
3315
+ `;
3316
+
3317
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/tsconfig.spec.json 1`] = `
3318
+ "{
3319
+ "extends": "../tsconfig.base.json",
3320
+ "compilerOptions": {
3321
+ "outDir": "./out-tsc/vitest",
3322
+ "types": [
3323
+ "vitest/globals",
3324
+ "vitest/importMeta",
3325
+ "vite/client",
3326
+ "node",
3327
+ "vitest",
3328
+ "@nx/react/typings/cssmodule.d.ts",
3329
+ "@nx/react/typings/image.d.ts"
3330
+ ]
3331
+ },
3332
+ "include": [
3333
+ "vite.config.ts",
3334
+ "vite.config.mts",
3335
+ "vitest.config.ts",
3336
+ "vitest.config.mts",
3337
+ "src/**/*.test.ts",
3338
+ "src/**/*.spec.ts",
3339
+ "src/**/*.test.tsx",
3340
+ "src/**/*.spec.tsx",
3341
+ "src/**/*.test.js",
3342
+ "src/**/*.spec.js",
3343
+ "src/**/*.test.jsx",
3344
+ "src/**/*.spec.jsx",
3345
+ "src/**/*.d.ts"
3346
+ ],
3347
+ "references": [
3348
+ {
3349
+ "path": "./tsconfig.app.json"
3350
+ }
3351
+ ]
3352
+ }
3353
+ "
3354
+ `;
3355
+
3356
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/vite.config.ts 1`] = `
3357
+ "import tailwindcss from '@tailwindcss/vite';
3358
+ import tsconfigPaths from 'vite-tsconfig-paths';
3359
+ import { resolve } from 'path';
3360
+ import { tanstackRouter } from '@tanstack/router-plugin/vite';
3361
+ /// <reference types='vitest' />
3362
+ import { defineConfig } from 'vite';
3363
+ import react from '@vitejs/plugin-react';
3364
+
3365
+ export default defineConfig(() => ({
3366
+ define: {
3367
+ global: {},
3368
+ },
3369
+ root: __dirname,
3370
+ cacheDir: '../node_modules/.vite/test-app',
3371
+ server: {
3372
+ port: 4200,
3373
+ host: 'localhost',
3374
+ },
3375
+ preview: {
3376
+ port: 4300,
3377
+ host: 'localhost',
3378
+ },
3379
+ plugins: [
3380
+ tanstackRouter({
3381
+ routesDirectory: resolve(__dirname, 'src/routes'),
3382
+ generatedRouteTree: resolve(__dirname, 'src/routeTree.gen.ts'),
3383
+ }),
3384
+ react(),
3385
+ tailwindcss(),
3386
+ tsconfigPaths(),
3387
+ ],
3388
+ build: {
3389
+ outDir: '../dist/test-app',
3390
+ emptyOutDir: true,
3391
+ reportCompressedSize: true,
3392
+ commonjsOptions: {
3393
+ transformMixedEsModules: true,
3394
+ },
3395
+ },
3396
+ test: {
3397
+ watch: false,
3398
+ globals: true,
3399
+ environment: 'jsdom',
3400
+ include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
3401
+ reporters: ['default'],
3402
+ coverage: {
3403
+ reportsDirectory: './test-output/vitest/coverage',
3404
+ provider: 'v8' as const,
3405
+ },
3406
+ passWithNoTests: true,
3407
+ },
3408
+ }));
3409
+ "
3410
+ `;
3411
+
3412
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > tsconfig.base.json 1`] = `
3413
+ "{
3414
+ "compilerOptions": {
3415
+ "paths": {
3416
+ ":proj/common-types": ["packages/common/types/src/index.ts"],
3417
+ ":proj/test-app": ["test-app/src/index.ts"],
3418
+ ":proj/common-constructs": ["packages/common/constructs/src/index.ts"]
3419
+ },
3420
+ "baseUrl": ".",
3421
+ "rootDir": "."
3422
+ }
3423
+ }
3424
+ "
3425
+ `;
3426
+
3427
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > tsconfig.json 1`] = `
3428
+ "{
3429
+ "references": [
3430
+ {
3431
+ "path": "./test-app"
3432
+ },
3433
+ {
3434
+ "path": "./packages/common/types"
3435
+ },
3436
+ {
3437
+ "path": "./packages/common/constructs"
3438
+ }
3439
+ ]
3440
+ }
3441
+ "
3442
+ `;
3443
+
3444
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > vitest.workspace.ts 1`] = `
3445
+ "export default [
3446
+ '**/vite.config.{mjs,js,ts,mts}',
3447
+ '**/vitest.config.{mjs,js,ts,mts}',
3448
+ ];
3449
+ "
3450
+ `;
3451
+
3452
+ exports[`react-website generator > should configure TypeScript correctly > tsconfig.json 1`] = `
3453
+ {
3454
+ "compilerOptions": {
3455
+ "module": "Preserve",
3456
+ "moduleResolution": "Bundler",
3457
+ },
3458
+ "extends": "../tsconfig.base.json",
3459
+ "files": [],
3460
+ "include": [],
3461
+ "references": [
3462
+ {
3463
+ "path": "./tsconfig.app.json",
3464
+ },
3465
+ {
3466
+ "path": "./tsconfig.spec.json",
3467
+ },
3468
+ ],
3469
+ }
3470
+ `;
3471
+
3472
+ exports[`react-website generator > should configure vite correctly > vite.config.ts 1`] = `
3473
+ "import tailwindcss from '@tailwindcss/vite';
3474
+ import tsconfigPaths from 'vite-tsconfig-paths';
3475
+ import { resolve } from 'path';
3476
+ import { tanstackRouter } from '@tanstack/router-plugin/vite';
3477
+ /// <reference types='vitest' />
3478
+ import { defineConfig } from 'vite';
3479
+ import react from '@vitejs/plugin-react';
3480
+
3481
+ export default defineConfig(() => ({
3482
+ define: {
3483
+ global: {},
3484
+ },
3485
+ root: __dirname,
3486
+ cacheDir: '../node_modules/.vite/test-app',
3487
+ server: {
3488
+ port: 4200,
3489
+ host: 'localhost',
3490
+ },
3491
+ preview: {
3492
+ port: 4300,
3493
+ host: 'localhost',
3494
+ },
3495
+ plugins: [
3496
+ tanstackRouter({
3497
+ routesDirectory: resolve(__dirname, 'src/routes'),
3498
+ generatedRouteTree: resolve(__dirname, 'src/routeTree.gen.ts'),
3499
+ }),
3500
+ react(),
3501
+ tailwindcss(),
3502
+ tsconfigPaths(),
3503
+ ],
3504
+ build: {
3505
+ outDir: '../dist/test-app',
3506
+ emptyOutDir: true,
3507
+ reportCompressedSize: true,
3508
+ commonjsOptions: {
3509
+ transformMixedEsModules: true,
3510
+ },
3511
+ },
3512
+ test: {
3513
+ watch: false,
3514
+ globals: true,
3515
+ environment: 'jsdom',
3516
+ include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
3517
+ reporters: ['default'],
3518
+ coverage: {
3519
+ reportsDirectory: './test-output/vitest/coverage',
3520
+ provider: 'v8' as const,
3521
+ },
3522
+ passWithNoTests: true,
3523
+ },
3524
+ }));
3525
+ "
3526
+ `;
3527
+
3528
+ exports[`react-website generator > should generate base files and structure > app-layout.tsx 1`] = `
3529
+ "import * as React from 'react';
3530
+ import { createContext, useCallback, useEffect, useState } from 'react';
3531
+ import Config from '../../config';
3532
+
3533
+ import {
3534
+ BreadcrumbGroup,
3535
+ BreadcrumbGroupProps,
3536
+ SideNavigation,
3537
+ TopNavigation,
3538
+ } from '@cloudscape-design/components';
3539
+ import CloudscapeAppLayout, {
3540
+ AppLayoutProps,
3541
+ } from '@cloudscape-design/components/app-layout';
3542
+ import { matchByPath, useLocation, useNavigate } from '@tanstack/react-router';
3543
+
3544
+ const getBreadcrumbs = (
3545
+ pathName: string,
3546
+ search: string,
3547
+ defaultBreadcrumb: string,
3548
+ availableRoutes?: string[],
3549
+ ) => {
3550
+ const segments = [
3551
+ defaultBreadcrumb,
3552
+ ...pathName.split('/').filter((segment) => segment !== ''),
3553
+ ];
3554
+
3555
+ return segments.map((segment, i) => {
3556
+ const href =
3557
+ i === 0
3558
+ ? '/'
3559
+ : \`/\${segments
3560
+ .slice(1, i + 1)
3561
+ .join('/')
3562
+ .replace('//', '/')}\`;
3563
+
3564
+ const matched =
3565
+ !availableRoutes || availableRoutes.find((r) => matchByPath(r, href, {}));
3566
+
3567
+ return {
3568
+ href: matched ? \`\${href}\${search}\` : '#',
3569
+ text: segment,
3570
+ };
3571
+ });
3572
+ };
3573
+
3574
+ export interface AppLayoutContext {
3575
+ appLayoutProps: AppLayoutProps;
3576
+ setAppLayoutProps: (props: AppLayoutProps) => void;
3577
+ displayHelpPanel: (helpContent: React.ReactNode) => void;
3578
+ }
3579
+
3580
+ /**
3581
+ * Context for updating/retrieving the AppLayout.
3582
+ */
3583
+ export const AppLayoutContext = createContext({
3584
+ appLayoutProps: {},
3585
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
3586
+ setAppLayoutProps: (_: AppLayoutProps) => {},
3587
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
3588
+ displayHelpPanel: (_: React.ReactNode) => {},
3589
+ });
3590
+
3591
+ /**
3592
+ * Defines the App layout and contains logic for routing.
3593
+ */
3594
+ const AppLayout: React.FC<React.PropsWithChildren> = ({ children }) => {
3595
+ const appLayout = React.useRef<AppLayoutProps.Ref>(null);
3596
+ const [appLayoutProps, setAppLayoutProps] = useState<AppLayoutProps>({});
3597
+ const setAppLayoutPropsSafe = useCallback(
3598
+ (props: AppLayoutProps) => {
3599
+ JSON.stringify(appLayoutProps) !== JSON.stringify(props) &&
3600
+ setAppLayoutProps(props);
3601
+ },
3602
+ [appLayoutProps],
3603
+ );
3604
+
3605
+ const navigate = useNavigate();
3606
+ const [activeBreadcrumbs, setActiveBreadcrumbs] = useState<
3607
+ BreadcrumbGroupProps.Item[]
3608
+ >([{ text: '/', href: '/' }]);
3609
+ const { pathname, search } = useLocation();
3610
+
3611
+ useEffect(() => {
3612
+ const breadcrumbs = getBreadcrumbs(
3613
+ pathname,
3614
+ Object.entries(search).reduce((p, [k, v]) => p + \`\${k}=\${v}\`, ''),
3615
+ '/',
3616
+ );
3617
+ setActiveBreadcrumbs(breadcrumbs);
3618
+ }, [pathname, search]);
3619
+
3620
+ const onNavigate = useCallback(
3621
+ (e: CustomEvent<{ href: string; external?: boolean }>) => {
3622
+ if (!e.detail.external) {
3623
+ e.preventDefault();
3624
+ setAppLayoutPropsSafe({
3625
+ contentType: undefined,
3626
+ });
3627
+ navigate({ to: e.detail.href });
3628
+ }
3629
+ },
3630
+ [navigate, setAppLayoutPropsSafe],
3631
+ );
3632
+
3633
+ return (
3634
+ <AppLayoutContext.Provider
3635
+ value={{
3636
+ appLayoutProps,
3637
+ setAppLayoutProps: setAppLayoutPropsSafe,
3638
+ displayHelpPanel: (helpContent: React.ReactNode) => {
3639
+ setAppLayoutPropsSafe({ tools: helpContent, toolsHide: false });
3640
+ appLayout.current?.openTools();
3641
+ },
3642
+ }}
3643
+ >
3644
+ <TopNavigation
3645
+ identity={{
3646
+ href: '/',
3647
+ title: Config.applicationName,
3648
+ logo: {
3649
+ src: Config.logo,
3650
+ },
3651
+ }}
3652
+ />
3653
+ <CloudscapeAppLayout
3654
+ ref={appLayout}
3655
+ breadcrumbs={
3656
+ <BreadcrumbGroup onFollow={onNavigate} items={activeBreadcrumbs} />
3657
+ }
3658
+ navigation={
3659
+ <SideNavigation
3660
+ header={{ text: Config.applicationName, href: '/' }}
3661
+ activeHref={pathname}
3662
+ onFollow={onNavigate}
3663
+ items={[{ text: 'Home', type: 'link', href: '/' }]}
3664
+ />
3665
+ }
3666
+ toolsHide
3667
+ content={children}
3668
+ {...appLayoutProps}
3669
+ />
3670
+ </AppLayoutContext.Provider>
3671
+ );
3672
+ };
3673
+
3674
+ export default AppLayout;
3675
+ "
3676
+ `;
3677
+
3678
+ exports[`react-website generator > should generate base files and structure > config.ts 1`] = `
3679
+ "export default {
3680
+ applicationName: 'test-app',
3681
+ logo: 'data:image/svg+xml;base64,PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KDTwhLS0gVXBsb2FkZWQgdG86IFNWRyBSZXBvLCB3d3cuc3ZncmVwby5jb20sIFRyYW5zZm9ybWVkIGJ5OiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4KPHN2ZyBmaWxsPSIjMjQ4YmFlIiB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHN0cm9rZT0iIzI0OGJhZSI+Cg08ZyBpZD0iU1ZHUmVwb19iZ0NhcnJpZXIiIHN0cm9rZS13aWR0aD0iMCIvPgoNPGcgaWQ9IlNWR1JlcG9fdHJhY2VyQ2FycmllciIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cg08ZyBpZD0iU1ZHUmVwb19pY29uQ2FycmllciI+Cg08dGl0bGU+aW9uaWNvbnMtdjVfbG9nb3M8L3RpdGxlPgoNPHBhdGggZD0iTTQxMC42NiwxODAuNzJoMHEtNy42Ny0yLjYyLTE1LjQ1LTQuODgsMS4yOS01LjI1LDIuMzgtMTAuNTZjMTEuNy01Ni45LDQuMDUtMTAyLjc0LTIyLjA2LTExNy44My0yNS0xNC40OC02NiwuNjEtMTA3LjM2LDM2LjY5cS02LjEsNS4zNC0xMS45NSwxMS0zLjktMy43Ni04LTcuMzZjLTQzLjM1LTM4LjU4LTg2LjgtNTQuODMtMTEyLjg4LTM5LjY5LTI1LDE0LjUxLTMyLjQzLDU3LjYtMjEuOSwxMTEuNTNxMS41OCw4LDMuNTUsMTUuOTNjLTYuMTUsMS43NS0xMi4wOSwzLjYyLTE3Ljc3LDUuNkM0OC40NiwxOTguOSwxNiwyMjYuNzMsMTYsMjU1LjU5YzAsMjkuODIsMzQuODQsNTkuNzIsODcuNzcsNzcuODVxNi40NCwyLjE5LDEzLDQuMDdRMTE0LjY0LDM0NiwxMTMsMzU0LjY4Yy0xMCw1My0yLjIsOTUuMDcsMjIuNzUsMTA5LjQ5LDI1Ljc3LDE0Ljg5LDY5LS40MSwxMTEuMTQtMzcuMzFxNS00LjM4LDEwLTkuMjUsNi4zMiw2LjExLDEzLDExLjg2YzQwLjgsMzUuMTgsODEuMDksNDkuMzksMTA2LDM0LjkzLDI1Ljc1LTE0Ljk0LDM0LjEyLTYwLjE0LDIzLjI1LTExNS4xM3EtMS4yNS02LjMtMi44OC0xMi44Niw0LjU2LTEuMzUsOC45My0yLjc5YzU1LTE4LjI3LDkwLjgzLTQ3LjgxLDkwLjgzLTc4QzQ5NiwyMjYuNjIsNDYyLjUsMTk4LjYxLDQxMC42NiwxODAuNzJabS0xMjktODEuMDhjMzUuNDMtMzAuOTEsNjguNTUtNDMuMTEsODMuNjUtMzQuMzloMGMxNi4wNyw5LjI5LDIyLjMyLDQ2Ljc1LDEyLjIyLDk1Ljg4cS0xLDQuOC0yLjE2LDkuNTdhNDg3LjgzLDQ4Ny44MywwLDAsMC02NC4xOC0xMC4xNiw0ODEuMjcsNDgxLjI3LDAsMCwwLTQwLjU3LTUwLjc1UTI3NiwxMDQuNTcsMjgxLjY0LDk5LjY0Wk0xNTcuNzMsMjgwLjI1cTYuNTEsMTIuNiwxMy42MSwyNC44OSw3LjIzLDEyLjU0LDE1LjA3LDI0LjcxYTQzNS4yOCw0MzUuMjgsMCwwLDEtNDQuMjQtNy4xM0MxNDYuNDEsMzA5LDE1MS42MywyOTQuNzUsMTU3LjczLDI4MC4yNVptMC00OC4zM2MtNi0xNC4xOS0xMS4wOC0yOC4xNS0xNS4yNS00MS42MywxMy43LTMuMDcsMjguMy01LjU4LDQzLjUyLTcuNDhxLTcuNjUsMTEuOTQtMTQuNzIsMjQuMjNUMTU3LjcsMjMxLjkyWm0xMC45LDI0LjE3cTkuNDgtMTkuNzcsMjAuNDItMzguNzhoMHExMC45My0xOSwyMy4yNy0zNy4xM2MxNC4yOC0xLjA4LDI4LjkyLTEuNjUsNDMuNzEtMS42NXMyOS41Mi41Nyw0My43OSwxLjY2cTEyLjIxLDE4LjA5LDIzLjEzLDM3dDIwLjY5LDM4LjZRMzM0LDI3NS42MywzMjMsMjk0LjczaDBxLTEwLjkxLDE5LTIzLDM3LjI0Yy0xNC4yNSwxLTI5LDEuNTUtNDQsMS41NXMtMjkuNDctLjQ3LTQzLjQ2LTEuMzhxLTEyLjQzLTE4LjE5LTIzLjQ2LTM3LjI5VDE2OC42LDI1Ni4wOVpNMzQwLjc1LDMwNXE3LjI1LTEyLjU4LDEzLjkyLTI1LjQ5aDBhNDQwLjQxLDQ0MC40MSwwLDAsMSwxNi4xMiw0Mi4zMkE0MzQuNDQsNDM0LjQ0LDAsMCwxLDMyNiwzMjkuNDhRMzMzLjYyLDMxNy4zOSwzNDAuNzUsMzA1Wm0xMy43Mi03My4wN3EtNi42NC0xMi42NS0xMy44MS0yNWgwcS03LTEyLjE4LTE0LjU5LTI0LjA2YzE1LjMxLDEuOTQsMzAsNC41Miw0My43Nyw3LjY3QTQzOS44OSw0MzkuODksMCwwLDEsMzU0LjQ3LDIzMS45M1pNMjU2LjIzLDEyNC40OGgwYTQzOS43NSw0MzkuNzUsMCwwLDEsMjguMjUsMzQuMThxLTI4LjM1LTEuMzUtNTYuNzQsMEMyMzcuMDcsMTQ2LjMyLDI0Ni42MiwxMzQuODcsMjU2LjIzLDEyNC40OFpNMTQ1LjY2LDY1Ljg2YzE2LjA2LTkuMzIsNTEuNTcsNCw4OSwzNy4yNywyLjM5LDIuMTMsNC44LDQuMzYsNy4yLDYuNjdBNDkxLjM3LDQ5MS4zNywwLDAsMCwyMDEsMTYwLjUxYTQ5OS4xMiw0OTkuMTIsMCwwLDAtNjQuMDYsMTBxLTEuODMtNy4zNi0zLjMtMTQuODJoMEMxMjQuNTksMTA5LjQ2LDEzMC41OCw3NC42MSwxNDUuNjYsNjUuODZaTTEyMi4yNSwzMTcuNzFxLTYtMS43MS0xMS44NS0zLjcxYy0yMy40LTgtNDIuNzMtMTguNDQtNTYtMjkuODFDNDIuNTIsMjc0LDM2LjUsMjYzLjgzLDM2LjUsMjU1LjU5YzAtMTcuNTEsMjYuMDYtMzkuODUsNjkuNTItNTVxOC4xOS0yLjg1LDE2LjUyLTUuMjFhNDkzLjU0LDQ5My41NCwwLDAsMCwyMy40LDYwLjc1QTUwMi40Niw1MDIuNDYsMCwwLDAsMTIyLjI1LDMxNy43MVptMTExLjEzLDkzLjY3Yy0xOC42MywxNi4zMi0zNy4yOSwyNy44OS01My43NCwzMy43MmgwYy0xNC43OCw1LjIzLTI2LjU1LDUuMzgtMzMuNjYsMS4yNy0xNS4xNC04Ljc1LTIxLjQ0LTQyLjU0LTEyLjg1LTg3Ljg2cTEuNTMtOCwzLjUtMTZhNDgwLjg1LDQ4MC44NSwwLDAsMCw2NC42OSw5LjM5LDUwMS4yLDUwMS4yLDAsMCwwLDQxLjIsNTFDMjM5LjU0LDQwNS44MywyMzYuNDksNDA4LjY1LDIzMy4zOCw0MTEuMzhabTIzLjQyLTIzLjIyYy05LjcyLTEwLjUxLTE5LjQyLTIyLjE0LTI4Ljg4LTM0LjY0cTEzLjc5LjU0LDI4LjA4LjU0YzkuNzgsMCwxOS40Ni0uMjEsMjktLjY0QTQzOS4zMyw0MzkuMzMsMCwwLDEsMjU2LjgsMzg4LjE2Wm0xMjQuNTIsMjguNTljLTIuODYsMTUuNDQtOC42MSwyNS43NC0xNS43MiwyOS44Ni0xNS4xMyw4Ljc4LTQ3LjQ4LTIuNjMtODIuMzYtMzIuNzItNC0zLjQ0LTgtNy4xMy0xMi4wNy0xMWE0ODQuNTQsNDg0LjU0LDAsMCwwLDQwLjIzLTUxLjIsNDc3Ljg0LDQ3Ny44NCwwLDAsMCw2NS0xMC4wNXExLjQ3LDUuOTQsMi42LDExLjY0aDBDMzgzLjgxLDM3Ny41OCwzODQuNSwzOTkuNTYsMzgxLjMyLDQxNi43NVptMTcuNC0xMDIuNjRoMGMtMi42Mi44Ny01LjMyLDEuNzEtOC4wNiwyLjUzYTQ4My4yNiw0ODMuMjYsMCwwLDAtMjQuMzEtNjAuOTQsNDgxLjUyLDQ4MS41MiwwLDAsMCwyMy4zNi02MC4wNmM0LjkxLDEuNDMsOS42OCwyLjkzLDE0LjI3LDQuNTIsNDQuNDIsMTUuMzIsNzEuNTIsMzgsNzEuNTIsNTUuNDNDNDc1LjUsMjc0LjE5LDQ0Ni4yMywyOTguMzMsMzk4LjcyLDMxNC4xMVoiLz4KDTxwYXRoIGQ9Ik0yNTYsMjk4LjU1YTQzLDQzLDAsMSwwLTQyLjg2LTQzQTQyLjkxLDQyLjkxLDAsMCwwLDI1NiwyOTguNTVaIi8+Cg08L2c+Cg08L3N2Zz4=',
3682
+ };
3683
+ "
3684
+ `;
3685
+
3686
+ exports[`react-website generator > should generate base files and structure > index.tsx 1`] = `
3687
+ "import {
3688
+ ContentLayout,
3689
+ Header,
3690
+ SpaceBetween,
3691
+ Container,
3692
+ } from '@cloudscape-design/components';
3693
+ import { createFileRoute } from '@tanstack/react-router';
3694
+
3695
+ export const Route = createFileRoute('/')({
3696
+ component: RouteComponent,
3697
+ });
3698
+
3699
+ function RouteComponent() {
3700
+ return (
3701
+ <ContentLayout header={<Header>Welcome</Header>}>
3702
+ <SpaceBetween size="l">
3703
+ <Container>Welcome to your new React website!</Container>
3704
+ </SpaceBetween>
3705
+ </ContentLayout>
3706
+ );
3707
+ }
3708
+ "
3709
+ `;
3710
+
3711
+ exports[`react-website generator > should generate base files and structure > main.tsx 1`] = `
3712
+ "import React from 'react';
3713
+ import { createRoot } from 'react-dom/client';
3714
+ import { I18nProvider } from '@cloudscape-design/components/i18n';
3715
+ import messages from '@cloudscape-design/components/i18n/messages/all.en';
3716
+ import '@cloudscape-design/global-styles/index.css';
3717
+ import { RouterProvider, createRouter } from '@tanstack/react-router';
3718
+ import { routeTree } from './routeTree.gen';
3719
+
3720
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
3721
+ export type RouterProviderContext = {};
3722
+
3723
+ const router = createRouter({
3724
+ routeTree,
3725
+ context: {},
3726
+ });
3727
+
3728
+ // Register the router instance for type safety
3729
+ declare module '@tanstack/react-router' {
3730
+ interface Register {
3731
+ router: typeof router;
3732
+ }
3733
+ }
3734
+
3735
+ const App = () => {
3736
+ return <RouterProvider router={router} context={{}} />;
3737
+ };
3738
+
3739
+ const root = document.getElementById('root');
3740
+ root &&
3741
+ createRoot(root).render(
3742
+ <React.StrictMode>
3743
+ <I18nProvider locale="en" messages={[messages]}>
3744
+ <App />
3745
+ </I18nProvider>
3746
+ </React.StrictMode>,
3747
+ );
3748
+ "
3749
+ `;
3750
+
3751
+ exports[`react-website generator > should generate shared constructs > common/constructs-app-index.ts 1`] = `
3752
+ "export * from './test-app.js';
3753
+ "
3754
+ `;
3755
+
3756
+ exports[`react-website generator > should generate shared constructs > common/constructs-core-index.ts 1`] = `
3757
+ "export * from './static-website.js';
3758
+ export * from './app.js';
3759
+ export * from './runtime-config.js';
3760
+ "
3761
+ `;
3762
+
3763
+ exports[`react-website generator > should generate shared constructs > common/constructs-core-static-website.ts 1`] = `
3764
+ "import { CfnJson, CfnOutput, RemovalPolicy, Stack, Token } from 'aws-cdk-lib';
3765
+ import { Distribution, ViewerProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
3766
+ import { S3BucketOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
3767
+ import {
3768
+ BlockPublicAccess,
3769
+ Bucket,
3770
+ BucketEncryption,
3771
+ IBucket,
3772
+ ObjectOwnership,
3773
+ } from 'aws-cdk-lib/aws-s3';
3774
+ import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';
3775
+ import { Construct } from 'constructs';
3776
+ import { RuntimeConfig } from './runtime-config.js';
3777
+ import { Key } from 'aws-cdk-lib/aws-kms';
3778
+ import { CfnWebACL } from 'aws-cdk-lib/aws-wafv2';
3779
+ const DEFAULT_RUNTIME_CONFIG_FILENAME = 'runtime-config.json';
3780
+
3781
+ export interface StaticWebsiteProps {
3782
+ readonly websiteFilePath: string;
3783
+ }
3784
+
3785
+ /**
3786
+ * Deploys a Static Website using by default a private S3 bucket as an origin and Cloudfront as the entrypoint.
3787
+ *
3788
+ * This construct configures a webAcl containing rules that are generally applicable to web applications. This
3789
+ * provides protection against exploitation of a wide range of vulnerabilities, including some of the high risk
3790
+ * and commonly occurring vulnerabilities described in OWASP publications such as OWASP Top 10.
3791
+ *
3792
+ */
3793
+ export class StaticWebsite extends Construct {
3794
+ public readonly websiteBucket: IBucket;
3795
+ public readonly cloudFrontDistribution: Distribution;
3796
+ public readonly bucketDeployment: BucketDeployment;
3797
+
3798
+ constructor(
3799
+ scope: Construct,
3800
+ id: string,
3801
+ { websiteFilePath }: StaticWebsiteProps,
3802
+ ) {
3803
+ super(scope, id);
3804
+ this.node.setContext(
3805
+ '@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy',
3806
+ true,
3807
+ );
3808
+
3809
+ const websiteKey = new Key(this, 'WebsiteKey', {
3810
+ enableKeyRotation: true,
3811
+ });
3812
+
3813
+ const accessLogsBucket = new Bucket(this, 'AccessLogsBucket', {
3814
+ versioned: false,
3815
+ enforceSSL: true,
3816
+ autoDeleteObjects: true,
3817
+ removalPolicy: RemovalPolicy.DESTROY,
3818
+ encryption: BucketEncryption.KMS,
3819
+ encryptionKey: websiteKey,
3820
+ objectOwnership: ObjectOwnership.OBJECT_WRITER,
3821
+ publicReadAccess: false,
3822
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
3823
+ });
3824
+ // S3 Bucket to hold website files
3825
+ this.websiteBucket = new Bucket(this, 'WebsiteBucket', {
3826
+ versioned: true,
3827
+ enforceSSL: true,
3828
+ autoDeleteObjects: true,
3829
+ removalPolicy: RemovalPolicy.DESTROY,
3830
+ encryption: BucketEncryption.KMS,
3831
+ encryptionKey: websiteKey,
3832
+ objectOwnership: ObjectOwnership.BUCKET_OWNER_ENFORCED,
3833
+ publicReadAccess: false,
3834
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
3835
+ serverAccessLogsPrefix: 'website-access-logs',
3836
+ serverAccessLogsBucket: accessLogsBucket,
3837
+ });
3838
+ // Web ACL
3839
+ const wafStack = new CloudfrontWebAcl(this, 'waf');
3840
+
3841
+ // Cloudfront Distribution
3842
+ const logBucket = new Bucket(this, 'DistributionLogBucket', {
3843
+ enforceSSL: true,
3844
+ autoDeleteObjects: true,
3845
+ removalPolicy: RemovalPolicy.DESTROY,
3846
+ encryption: BucketEncryption.KMS,
3847
+ encryptionKey: websiteKey,
3848
+ objectOwnership: ObjectOwnership.BUCKET_OWNER_PREFERRED,
3849
+ publicReadAccess: false,
3850
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
3851
+ serverAccessLogsPrefix: 'distribution-access-logs',
3852
+ serverAccessLogsBucket: accessLogsBucket,
3853
+ });
3854
+ const defaultRootObject = 'index.html';
3855
+ this.cloudFrontDistribution = new Distribution(
3856
+ this,
3857
+ 'CloudfrontDistribution',
3858
+ {
3859
+ webAclId: wafStack.wafArn,
3860
+ enableLogging: true,
3861
+ logBucket: logBucket,
3862
+ defaultBehavior: {
3863
+ origin: S3BucketOrigin.withOriginAccessControl(this.websiteBucket),
3864
+ viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
3865
+ },
3866
+ defaultRootObject,
3867
+ errorResponses: [
3868
+ {
3869
+ httpStatus: 404, // We need to redirect "key not found errors" to index.html for single page apps
3870
+ responseHttpStatus: 200,
3871
+ responsePagePath: \`/\${defaultRootObject}\`,
3872
+ },
3873
+ {
3874
+ httpStatus: 403, // We need to redirect reloads from paths (e.g. /foo/bar) to index.html for single page apps
3875
+ responseHttpStatus: 200,
3876
+ responsePagePath: \`/\${defaultRootObject}\`,
3877
+ },
3878
+ ],
3879
+ },
3880
+ );
3881
+ // Deploy Website
3882
+ this.bucketDeployment = new BucketDeployment(this, 'WebsiteDeployment', {
3883
+ sources: [
3884
+ Source.asset(websiteFilePath),
3885
+ Source.jsonData(
3886
+ DEFAULT_RUNTIME_CONFIG_FILENAME,
3887
+ this.resolveTokens(RuntimeConfig.ensure(this).config),
3888
+ ),
3889
+ ],
3890
+ destinationBucket: this.websiteBucket,
3891
+ // Files in the distribution's edge caches will be invalidated after files are uploaded to the destination bucket.
3892
+ distribution: this.cloudFrontDistribution,
3893
+ memoryLimit: 1024,
3894
+ });
3895
+ new CfnOutput(this, 'DistributionDomainName', {
3896
+ value: this.cloudFrontDistribution.domainName,
3897
+ });
3898
+ new CfnOutput(this, 'WebsiteBucketName', {
3899
+ value: this.websiteBucket.bucketName,
3900
+ });
3901
+ }
3902
+ private resolveTokens = (payload: any) => {
3903
+ const _payload: Record<string, any> = {};
3904
+ Object.entries(payload).forEach(([key, value]) => {
3905
+ if (
3906
+ Token.isUnresolved(value) ||
3907
+ (typeof value === 'string' && value.endsWith('}}'))
3908
+ ) {
3909
+ _payload[key] = new CfnJson(this, \`ResolveToken-\${key}\`, {
3910
+ value,
3911
+ }).value;
3912
+ } else if (typeof value === 'object') {
3913
+ _payload[key] = this.resolveTokens(value);
3914
+ } else if (Array.isArray(value)) {
3915
+ _payload[key] = value.map((v) => this.resolveTokens(v));
3916
+ } else {
3917
+ _payload[key] = value;
3918
+ }
3919
+ });
3920
+ return _payload;
3921
+ };
3922
+ }
3923
+
3924
+ export class CloudfrontWebAcl extends Stack {
3925
+ public readonly wafArn;
3926
+ constructor(scope: Construct, id: string) {
3927
+ super(scope, id, {
3928
+ env: {
3929
+ region: 'us-east-1',
3930
+ account: Stack.of(scope).account,
3931
+ },
3932
+ crossRegionReferences: true,
3933
+ });
3934
+
3935
+ this.wafArn = new CfnWebACL(this, 'WebAcl', {
3936
+ defaultAction: { allow: {} },
3937
+ scope: 'CLOUDFRONT',
3938
+ visibilityConfig: {
3939
+ cloudWatchMetricsEnabled: true,
3940
+ metricName: id,
3941
+ sampledRequestsEnabled: true,
3942
+ },
3943
+ rules: [
3944
+ {
3945
+ name: 'CRSRule',
3946
+ priority: 0,
3947
+ statement: {
3948
+ managedRuleGroupStatement: {
3949
+ name: 'AWSManagedRulesCommonRuleSet',
3950
+ vendorName: 'AWS',
3951
+ },
3952
+ },
3953
+ visibilityConfig: {
3954
+ cloudWatchMetricsEnabled: true,
3955
+ metricName: 'MetricForWebACLCDK-CRS',
3956
+ sampledRequestsEnabled: true,
3957
+ },
3958
+ overrideAction: {
3959
+ none: {},
3960
+ },
3961
+ },
3962
+ ],
3963
+ }).attrArn;
3964
+ }
3965
+ }
3966
+ "
3967
+ `;
3968
+
3969
+ exports[`react-website generator > should generate shared constructs > test-app.ts 1`] = `
3970
+ "import * as url from 'url';
3971
+ import { Construct } from 'constructs';
3972
+ import { StaticWebsite } from '../../core/index.js';
3973
+
3974
+ export class TestApp extends StaticWebsite {
3975
+ constructor(scope: Construct, id: string) {
3976
+ super(scope, id, {
3977
+ websiteFilePath: url.fileURLToPath(
3978
+ new URL('../../../../../../dist/test-app/bundle', import.meta.url),
3979
+ ),
3980
+ });
3981
+ }
3982
+ }
3983
+ "
3984
+ `;
3985
+
3986
+ exports[`react-website generator > should handle custom directory option > custom-dir-main.tsx 1`] = `
3987
+ "import React from 'react';
3988
+ import { createRoot } from 'react-dom/client';
3989
+ import { I18nProvider } from '@cloudscape-design/components/i18n';
3990
+ import messages from '@cloudscape-design/components/i18n/messages/all.en';
3991
+ import '@cloudscape-design/global-styles/index.css';
3992
+ import { RouterProvider, createRouter } from '@tanstack/react-router';
3993
+ import { routeTree } from './routeTree.gen';
3994
+
3995
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
3996
+ export type RouterProviderContext = {};
3997
+
3998
+ const router = createRouter({
3999
+ routeTree,
4000
+ context: {},
4001
+ });
4002
+
4003
+ // Register the router instance for type safety
4004
+ declare module '@tanstack/react-router' {
4005
+ interface Register {
4006
+ router: typeof router;
4007
+ }
4008
+ }
4009
+
4010
+ const App = () => {
4011
+ return <RouterProvider router={router} context={{}} />;
4012
+ };
4013
+
4014
+ const root = document.getElementById('root');
4015
+ root &&
4016
+ createRoot(root).render(
4017
+ <React.StrictMode>
4018
+ <I18nProvider locale="en" messages={[messages]}>
4019
+ <App />
4020
+ </I18nProvider>
4021
+ </React.StrictMode>,
4022
+ );
4023
+ "
4024
+ `;
4025
+
4026
+ exports[`react-website generator > should handle npm scope prefix correctly > scoped-dependencies 1`] = `
4027
+ {
4028
+ "@cloudscape-design/board-components": "^3.0.94",
4029
+ "@cloudscape-design/components": "^3.0.928",
4030
+ "@cloudscape-design/global-styles": "^1.0.38",
4031
+ "@tanstack/react-router": "^1.121.16",
4032
+ "aws-cdk-lib": "^2.200.0",
4033
+ "constructs": "^10.4.2",
4034
+ "react": "19.0.0",
4035
+ "react-dom": "19.0.0",
4036
+ "tailwindcss": "^4.1.11",
4037
+ }
4038
+ `;