@remix-run/cli 0.1.0 → 0.3.0

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 (110) hide show
  1. package/README.md +0 -3
  2. package/dist/lib/bootstrap-project.d.ts.map +1 -1
  3. package/dist/lib/bootstrap-project.js +32 -9
  4. package/dist/lib/cli.d.ts +29 -0
  5. package/dist/lib/cli.d.ts.map +1 -1
  6. package/dist/lib/cli.js +33 -14
  7. package/dist/lib/commands/completion.d.ts.map +1 -1
  8. package/dist/lib/commands/completion.js +5 -1
  9. package/dist/lib/commands/doctor.js +18 -18
  10. package/dist/lib/commands/help.d.ts.map +1 -1
  11. package/dist/lib/commands/help.js +9 -33
  12. package/dist/lib/commands/routes.js +3 -3
  13. package/dist/lib/commands/test.d.ts +1 -1
  14. package/dist/lib/commands/test.d.ts.map +1 -1
  15. package/dist/lib/commands/test.js +8 -4
  16. package/dist/lib/completion.d.ts.map +1 -1
  17. package/dist/lib/completion.js +4 -106
  18. package/dist/lib/controller-files.d.ts +0 -1
  19. package/dist/lib/controller-files.d.ts.map +1 -1
  20. package/dist/lib/controller-files.js +3 -5
  21. package/dist/lib/controller-ownership.d.ts +9 -9
  22. package/dist/lib/controller-ownership.d.ts.map +1 -1
  23. package/dist/lib/controller-ownership.js +56 -91
  24. package/dist/lib/doctor/controller-findings.d.ts +1 -1
  25. package/dist/lib/doctor/controller-findings.d.ts.map +1 -1
  26. package/dist/lib/doctor/controller-findings.js +15 -87
  27. package/dist/lib/doctor/controller-fix-plans.d.ts.map +1 -1
  28. package/dist/lib/doctor/controller-fix-plans.js +13 -24
  29. package/dist/lib/doctor/controller-placeholders.d.ts +2 -3
  30. package/dist/lib/doctor/controller-placeholders.d.ts.map +1 -1
  31. package/dist/lib/doctor/controller-placeholders.js +18 -149
  32. package/dist/lib/doctor/controllers.js +1 -1
  33. package/dist/lib/doctor/project.js +60 -52
  34. package/dist/lib/doctor/types.d.ts +2 -2
  35. package/dist/lib/doctor/types.d.ts.map +1 -1
  36. package/dist/lib/errors.d.ts +0 -6
  37. package/dist/lib/errors.d.ts.map +1 -1
  38. package/dist/lib/errors.js +0 -11
  39. package/dist/lib/load-route-map-worker.js +17 -9
  40. package/dist/lib/route-map.d.ts +1 -1
  41. package/dist/lib/route-map.d.ts.map +1 -1
  42. package/dist/lib/route-map.js +29 -17
  43. package/package.json +4 -5
  44. package/src/lib/bootstrap-project.ts +39 -13
  45. package/src/lib/cli.ts +46 -15
  46. package/src/lib/commands/completion.ts +6 -1
  47. package/src/lib/commands/doctor.ts +18 -21
  48. package/src/lib/commands/help.ts +9 -43
  49. package/src/lib/commands/routes.ts +3 -3
  50. package/src/lib/commands/test.ts +10 -4
  51. package/src/lib/completion.ts +4 -151
  52. package/src/lib/controller-files.ts +4 -8
  53. package/src/lib/controller-ownership.ts +78 -141
  54. package/src/lib/doctor/controller-findings.ts +20 -97
  55. package/src/lib/doctor/controller-fix-plans.ts +13 -29
  56. package/src/lib/doctor/controller-placeholders.ts +17 -189
  57. package/src/lib/doctor/controllers.ts +1 -1
  58. package/src/lib/doctor/project.ts +60 -52
  59. package/src/lib/doctor/types.ts +1 -5
  60. package/src/lib/errors.ts +0 -12
  61. package/src/lib/load-route-map-worker.ts +19 -10
  62. package/src/lib/route-map.ts +61 -16
  63. package/template/.agents/skills/remix/SKILL.md +588 -0
  64. package/template/.agents/skills/remix/references/animate-elements.md +195 -0
  65. package/template/.agents/skills/remix/references/assets-and-browser-modules.md +130 -0
  66. package/template/.agents/skills/remix/references/auth-and-sessions.md +443 -0
  67. package/template/.agents/skills/remix/references/component-model.md +282 -0
  68. package/template/.agents/skills/remix/references/create-mixins.md +158 -0
  69. package/template/.agents/skills/remix/references/data-and-validation.md +379 -0
  70. package/template/.agents/skills/remix/references/hydration-frames-navigation.md +297 -0
  71. package/template/.agents/skills/remix/references/middleware-and-server.md +233 -0
  72. package/template/.agents/skills/remix/references/mixins-styling-events.md +213 -0
  73. package/template/.agents/skills/remix/references/routing-and-controllers.md +391 -0
  74. package/template/.agents/skills/remix/references/testing-patterns.md +172 -0
  75. package/{bootstrap → template}/AGENTS.md +13 -8
  76. package/template/README.md +29 -0
  77. package/template/app/actions/controller.tsx +18 -0
  78. package/template/app/assets/entry.ts +8 -0
  79. package/template/app/assets/prompt-button.tsx +163 -0
  80. package/template/app/assets.ts +20 -0
  81. package/template/app/middleware/render.tsx +43 -0
  82. package/template/app/router.ts +20 -0
  83. package/template/app/routes.ts +6 -0
  84. package/template/app/ui/document.tsx +33 -0
  85. package/template/app/ui/scaffold-home-page.tsx +527 -0
  86. package/template/gitignore +4 -0
  87. package/{bootstrap → template}/package.json +5 -6
  88. package/template/public/favicon.svg +11 -0
  89. package/{bootstrap → template}/server.ts +4 -5
  90. package/{bootstrap → template}/tsconfig.json +3 -3
  91. package/bootstrap/README.md +0 -27
  92. package/bootstrap/app/controllers/auth.tsx +0 -21
  93. package/bootstrap/app/controllers/home.tsx +0 -26
  94. package/bootstrap/app/router.ts +0 -10
  95. package/bootstrap/app/routes.ts +0 -6
  96. package/bootstrap/app/ui/document.tsx +0 -21
  97. package/bootstrap/app/ui/layout.tsx +0 -22
  98. package/bootstrap/app/utils/render.tsx +0 -7
  99. package/dist/lib/commands/skills.d.ts +0 -6
  100. package/dist/lib/commands/skills.d.ts.map +0 -1
  101. package/dist/lib/commands/skills.js +0 -222
  102. package/dist/lib/skills-cache.d.ts +0 -19
  103. package/dist/lib/skills-cache.d.ts.map +0 -1
  104. package/dist/lib/skills-cache.js +0 -89
  105. package/dist/lib/skills.d.ts +0 -30
  106. package/dist/lib/skills.d.ts.map +0 -1
  107. package/dist/lib/skills.js +0 -441
  108. package/src/lib/commands/skills.ts +0 -306
  109. package/src/lib/skills-cache.ts +0 -140
  110. package/src/lib/skills.ts +0 -706
@@ -1,7 +1,8 @@
1
1
  import * as fs from 'node:fs/promises';
2
2
  import * as path from 'node:path';
3
3
  import { getOwnerCandidateForExtension, getOwnerFileExtension, } from "../controller-files.js";
4
- import { renderActionPlaceholder, renderControllerPlaceholder } from "./controller-placeholders.js";
4
+ import { ROOT_ROUTE_NAME } from "../controller-ownership.js";
5
+ import { renderControllerPlaceholder } from "./controller-placeholders.js";
5
6
  const OWNER_EXTENSION_PRIORITY = ['.tsx', '.ts', '.jsx', '.js'];
6
7
  export async function getControllerFixPlans(appRoot, tree, ownership) {
7
8
  let routeNodesByName = getRouteNodesByName(tree);
@@ -31,51 +32,33 @@ export async function getControllerFixPlans(appRoot, tree, ownership) {
31
32
  if (routeNode == null || entryPath == null) {
32
33
  continue;
33
34
  }
34
- let contents = subtree.kind === 'action'
35
- ? renderActionPlaceholder(routeNode, entryPath)
36
- : renderControllerPlaceholder(routeNode, entryPath, resolvedEntryPathByRouteName);
35
+ let contents = renderControllerPlaceholder(routeNode, entryPath);
37
36
  fixPlans.push({
38
37
  code,
39
38
  contents,
40
39
  kind: 'create-file',
41
40
  path: entryPath,
42
41
  routeName: subtree.routeName,
43
- suite: 'controllers',
42
+ suite: 'actions',
44
43
  });
45
44
  }
46
45
  return fixPlans;
47
46
  }
48
47
  function getFixCodeForSubtree(subtree) {
49
- if (subtree.actualEntryPaths.length > 1 || subtree.actualAlternatePaths.length > 1) {
48
+ if (subtree.actualEntryPaths.length > 1) {
50
49
  return null;
51
50
  }
52
51
  if (subtree.actualEntryPath != null) {
53
52
  return null;
54
53
  }
55
- if (subtree.actualAlternatePath != null) {
56
- return 'wrong-owner-kind';
57
- }
58
- if (subtree.kind === 'controller') {
59
- return subtree.claimedFilePaths.length > 0 ? 'incomplete-controller' : 'missing-owner';
60
- }
61
- if (subtree.claimedFilePaths.length > 0) {
62
- return null;
63
- }
64
- return 'missing-owner';
54
+ return subtree.claimedFilePaths.length > 0 ? 'incomplete-controller' : 'missing-owner';
65
55
  }
66
56
  function inferOwnerExtension(subtree, ownership, hasTsconfig) {
67
57
  let subtreeExtension = getMostCommonOwnerExtension(subtree.claimedRouteLocalFilePaths);
68
58
  if (subtreeExtension != null) {
69
59
  return subtreeExtension;
70
60
  }
71
- let alternateExtension = getMostCommonOwnerExtension(subtree.actualAlternatePaths);
72
- if (alternateExtension != null) {
73
- return alternateExtension;
74
- }
75
- let projectExtension = getMostCommonOwnerExtension([
76
- ...ownership.scan.actionEntryPaths,
77
- ...ownership.scan.controllerEntryPaths,
78
- ]);
61
+ let projectExtension = getMostCommonOwnerExtension([...ownership.scan.controllerEntryPaths]);
79
62
  if (projectExtension != null) {
80
63
  return projectExtension;
81
64
  }
@@ -106,6 +89,12 @@ function getMostCommonOwnerExtension(filePaths) {
106
89
  }
107
90
  function getRouteNodesByName(tree) {
108
91
  let routeNodesByName = new Map();
92
+ routeNodesByName.set(ROOT_ROUTE_NAME, {
93
+ children: tree,
94
+ key: ROOT_ROUTE_NAME,
95
+ kind: 'group',
96
+ name: ROOT_ROUTE_NAME,
97
+ });
109
98
  function visit(nodes) {
110
99
  for (let node of nodes) {
111
100
  routeNodesByName.set(node.name, node);
@@ -1,4 +1,3 @@
1
- import type { OwnershipRouteNode } from '../controller-ownership.ts';
2
- export declare function renderActionPlaceholder(routeNode: OwnershipRouteNode, entryPath: string): string;
3
- export declare function renderControllerPlaceholder(routeNode: OwnershipRouteNode, entryPath: string, resolvedEntryPathByRouteName: Map<string, string>): string;
1
+ import { type OwnershipRouteNode } from '../controller-ownership.ts';
2
+ export declare function renderControllerPlaceholder(routeNode: OwnershipRouteNode, entryPath: string): string;
4
3
  //# sourceMappingURL=controller-placeholders.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"controller-placeholders.d.ts","sourceRoot":"","sources":["../../../src/lib/doctor/controller-placeholders.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAmDpE,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAgChG;AAED,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,kBAAkB,EAC7B,SAAS,EAAE,MAAM,EACjB,4BAA4B,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAChD,MAAM,CAkCR"}
1
+ {"version":3,"file":"controller-placeholders.d.ts","sourceRoot":"","sources":["../../../src/lib/doctor/controller-placeholders.ts"],"names":[],"mappings":"AAGA,OAAO,EAAmB,KAAK,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAErF,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,kBAAkB,EAC7B,SAAS,EAAE,MAAM,GAChB,MAAM,CAyBR"}
@@ -1,92 +1,13 @@
1
1
  import * as path from 'node:path';
2
2
  import { getOwnerFileExtension } from "../controller-files.js";
3
- const RESERVED_BINDING_IDENTIFIERS = new Set([
4
- 'await',
5
- 'break',
6
- 'case',
7
- 'catch',
8
- 'class',
9
- 'const',
10
- 'continue',
11
- 'debugger',
12
- 'default',
13
- 'delete',
14
- 'do',
15
- 'else',
16
- 'enum',
17
- 'export',
18
- 'extends',
19
- 'false',
20
- 'finally',
21
- 'for',
22
- 'function',
23
- 'if',
24
- 'implements',
25
- 'import',
26
- 'in',
27
- 'instanceof',
28
- 'interface',
29
- 'let',
30
- 'new',
31
- 'null',
32
- 'package',
33
- 'private',
34
- 'protected',
35
- 'public',
36
- 'return',
37
- 'static',
38
- 'super',
39
- 'switch',
40
- 'this',
41
- 'throw',
42
- 'true',
43
- 'try',
44
- 'typeof',
45
- 'var',
46
- 'void',
47
- 'while',
48
- 'with',
49
- 'yield',
50
- ]);
51
- export function renderActionPlaceholder(routeNode, entryPath) {
52
- let routeMessage = `TODO: implement routes.${routeNode.name}`;
53
- let extension = getOwnerFileExtension(entryPath);
54
- let exportName = getActionExportName(routeNode.key);
55
- if (extension === '.js' || extension === '.jsx') {
56
- return [
57
- `export const ${exportName} = {`,
58
- ` handler() {`,
59
- ` return new Response(${JSON.stringify(routeMessage)})`,
60
- ` },`,
61
- `}`,
62
- '',
63
- ].join('\n');
64
- }
65
- let routeExpression = getRouteAccessExpression(routeNode.name);
66
- let routesImportPath = getRelativeImportPath(entryPath, 'app/routes.ts');
67
- let method = routeNode.method ?? 'ANY';
68
- return [
69
- `import type { BuildAction } from 'remix/fetch-router'`,
70
- '',
71
- `import type { routes } from '${routesImportPath}'`,
72
- '',
73
- `export const ${exportName}: BuildAction<'${method}', typeof ${routeExpression}> = {`,
74
- ` handler() {`,
75
- ` return new Response(${JSON.stringify(routeMessage)})`,
76
- ` },`,
77
- `}`,
78
- '',
79
- ].join('\n');
80
- }
81
- export function renderControllerPlaceholder(routeNode, entryPath, resolvedEntryPathByRouteName) {
3
+ import { ROOT_ROUTE_NAME } from "../controller-ownership.js";
4
+ export function renderControllerPlaceholder(routeNode, entryPath) {
82
5
  let extension = getOwnerFileExtension(entryPath);
83
6
  let lines = [];
84
- let childImports = getControllerChildImports(routeNode, entryPath, resolvedEntryPathByRouteName);
85
- let actionEntries = routeNode.children.map((childNode) => renderControllerActionEntry(childNode, entryPath, resolvedEntryPathByRouteName));
7
+ let actionEntries = routeNode.children
8
+ .filter((childNode) => childNode.kind === 'route')
9
+ .map((childNode) => renderControllerActionEntry(childNode));
86
10
  if (extension === '.js' || extension === '.jsx') {
87
- if (childImports.length > 0) {
88
- lines.push(...childImports, '');
89
- }
90
11
  lines.push('export default {', ' actions: {');
91
12
  lines.push(...actionEntries);
92
13
  lines.push(' },', '}', '');
@@ -94,57 +15,24 @@ export function renderControllerPlaceholder(routeNode, entryPath, resolvedEntryP
94
15
  }
95
16
  let routeExpression = getRouteAccessExpression(routeNode.name);
96
17
  let routesImportPath = getRelativeImportPath(entryPath, 'app/routes.ts');
97
- lines.push(`import type { Controller } from 'remix/fetch-router'`, '');
98
- lines.push(`import type { routes } from '${routesImportPath}'`);
99
- if (childImports.length > 0) {
100
- lines.push('', ...childImports);
101
- }
102
- lines.push('', 'export default {', ' actions: {');
18
+ lines.push(`import { createController } from 'remix/router'`, '');
19
+ lines.push(`import { routes } from '${routesImportPath}'`);
20
+ lines.push('', `export default createController(${routeExpression}, {`, ' actions: {');
103
21
  lines.push(...actionEntries);
104
- lines.push(' },', `} satisfies Controller<typeof ${routeExpression}>`, '');
22
+ lines.push(' },', '})', '');
105
23
  return lines.join('\n');
106
24
  }
107
- function getControllerChildImports(routeNode, entryPath, resolvedEntryPathByRouteName) {
108
- let imports = [];
109
- for (let childNode of routeNode.children) {
110
- if (childNode.kind !== 'group') {
111
- continue;
112
- }
113
- let childEntryPath = resolvedEntryPathByRouteName.get(childNode.name);
114
- if (childEntryPath == null) {
115
- continue;
116
- }
117
- imports.push(`import ${getControllerImportName(childNode.key)} from '${getRelativeImportPath(entryPath, childEntryPath)}'`);
118
- }
119
- return imports;
120
- }
121
- function renderControllerActionEntry(childNode, entryPath, resolvedEntryPathByRouteName) {
122
- if (childNode.kind === 'route') {
123
- return [
124
- ` ${formatObjectKey(childNode.key)}() {`,
125
- ` return new Response(${JSON.stringify(`TODO: implement routes.${childNode.name}`)})`,
126
- ` },`,
127
- ].join('\n');
128
- }
129
- let childEntryPath = resolvedEntryPathByRouteName.get(childNode.name);
130
- if (childEntryPath != null) {
131
- return ` ${formatObjectKey(childNode.key)}: ${getControllerImportName(childNode.key)},`;
132
- }
133
- return ` ${formatObjectKey(childNode.key)}: ${renderInlineControllerPlaceholder(childNode)},`;
134
- }
135
- function renderInlineControllerPlaceholder(routeNode) {
136
- let childEntries = routeNode.children.map((childNode) => childNode.kind === 'route'
137
- ? `${formatObjectKey(childNode.key)}() { return new Response(${JSON.stringify(`TODO: implement routes.${childNode.name}`)}) }`
138
- : `${formatObjectKey(childNode.key)}: ${renderInlineControllerPlaceholder(childNode)}`);
139
- return `{ actions: { ${childEntries.join(', ')} } }`;
140
- }
141
- function getControllerImportName(key) {
142
- return `${toIdentifier(key)}Controller`;
143
- }
144
- function getActionExportName(key) {
145
- return toIdentifier(key);
25
+ function renderControllerActionEntry(childNode) {
26
+ return [
27
+ ` ${formatObjectKey(childNode.key)}() {`,
28
+ ` return new Response(${JSON.stringify(`TODO: implement routes.${childNode.name}`)})`,
29
+ ` },`,
30
+ ].join('\n');
146
31
  }
147
32
  function getRouteAccessExpression(routeName) {
33
+ if (routeName === ROOT_ROUTE_NAME) {
34
+ return 'routes';
35
+ }
148
36
  let segments = routeName.split('.');
149
37
  let expression = 'routes';
150
38
  for (let segment of segments) {
@@ -159,25 +47,6 @@ function getRelativeImportPath(fromFilePath, toFilePath) {
159
47
  function formatObjectKey(key) {
160
48
  return isIdentifier(key) ? key : JSON.stringify(key);
161
49
  }
162
- function toIdentifier(value) {
163
- let parts = value.split(/[^A-Za-z0-9_$]+/).filter(Boolean);
164
- if (parts.length === 0) {
165
- return 'route';
166
- }
167
- let identifier = parts
168
- .map((part, index) => index === 0 ? part.replace(/^./, (char) => char.toLowerCase()) : capitalize(part))
169
- .join('');
170
- if (!/^[A-Za-z_$]/.test(identifier)) {
171
- return `route${capitalize(identifier)}`;
172
- }
173
- if (RESERVED_BINDING_IDENTIFIERS.has(identifier)) {
174
- return `route${capitalize(identifier)}`;
175
- }
176
- return identifier;
177
- }
178
- function capitalize(value) {
179
- return value.length === 0 ? value : `${value[0].toUpperCase()}${value.slice(1)}`;
180
- }
181
50
  function isIdentifier(value) {
182
51
  return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value);
183
52
  }
@@ -8,6 +8,6 @@ export async function checkControllerConventions(appRoot, tree) {
8
8
  let findings = getControllerFindings(ownership, fixPlans);
9
9
  return {
10
10
  fixPlans,
11
- suite: createDoctorSuite('controllers', findings),
11
+ suite: createDoctorSuite('actions', findings),
12
12
  };
13
13
  }
@@ -39,7 +39,7 @@ export async function checkProject(projectRoot) {
39
39
  }
40
40
  export async function getProjectFixPlans(projectRoot) {
41
41
  let routesFile = path.join(projectRoot, 'app', 'routes.ts');
42
- let homeActionPath = normalizeRelativePath(path.join('app', 'controllers', `home${await inferHomeOwnerExtension(projectRoot)}`));
42
+ let homeActionPath = normalizeRelativePath(path.join('app', 'actions', `controller${await inferHomeOwnerExtension(projectRoot)}`));
43
43
  if (await pathExists(routesFile)) {
44
44
  let routesSource = await fs.readFile(routesFile, 'utf8');
45
45
  if (!hasOnlyWhitespaceAndComments(routesSource)) {
@@ -181,8 +181,8 @@ function hasOnlyWhitespaceAndComments(source) {
181
181
  return true;
182
182
  }
183
183
  async function inferHomeOwnerExtension(projectRoot) {
184
- let controllersDir = path.join(projectRoot, 'app', 'controllers');
185
- let extensions = await collectOwnerExtensions(controllersDir);
184
+ let actionsDir = path.join(projectRoot, 'app', 'actions');
185
+ let extensions = await collectOwnerExtensions(actionsDir);
186
186
  if (extensions.length > 0) {
187
187
  return getMostCommonExtension(extensions);
188
188
  }
@@ -239,7 +239,7 @@ function getMostCommonExtension(extensions) {
239
239
  }
240
240
  function renderDefaultRoutesFile() {
241
241
  return [
242
- `import { route } from 'remix/fetch-router/routes'`,
242
+ `import { route } from 'remix/routes'`,
243
243
  '',
244
244
  'export const routes = route({',
245
245
  ` home: '/',`,
@@ -257,22 +257,24 @@ function renderDefaultHomeAction(entryPath) {
257
257
  `import { html } from 'remix/html-template'`,
258
258
  `import { createHtmlResponse } from 'remix/response/html'`,
259
259
  '',
260
- 'export const home = {',
261
- ' handler() {',
262
- ' let page = html`',
263
- ' <html lang="en">',
264
- ' <head>',
265
- ' <meta charset="utf-8" />',
266
- ' <meta name="viewport" content="width=device-width, initial-scale=1" />',
267
- ' <title>Home</title>',
268
- ' </head>',
269
- ' <body>',
270
- ' <h1>Home</h1>',
271
- ' <p>Update app/routes.ts and app/controllers/home to keep building your app.</p>',
272
- ' </body>',
273
- ' </html>',
274
- ' `',
275
- ' return createHtmlResponse(page)',
260
+ 'export default {',
261
+ ' actions: {',
262
+ ' home() {',
263
+ ' let page = html`',
264
+ ' <html lang="en">',
265
+ ' <head>',
266
+ ' <meta charset="utf-8" />',
267
+ ' <meta name="viewport" content="width=device-width, initial-scale=1" />',
268
+ ' <title>Home</title>',
269
+ ' </head>',
270
+ ' <body>',
271
+ ' <h1>Home</h1>',
272
+ ' <p>Update app/routes.ts and app/actions/controller to keep building your app.</p>',
273
+ ' </body>',
274
+ ' </html>',
275
+ ' `',
276
+ ' return createHtmlResponse(page)',
277
+ ' },',
276
278
  ' },',
277
279
  '}',
278
280
  '',
@@ -280,30 +282,32 @@ function renderDefaultHomeAction(entryPath) {
280
282
  }
281
283
  if (extension === '.ts') {
282
284
  return [
283
- `import type { BuildAction } from 'remix/fetch-router'`,
285
+ `import { createController } from 'remix/router'`,
284
286
  `import { html } from 'remix/html-template'`,
285
287
  `import { createHtmlResponse } from 'remix/response/html'`,
286
288
  '',
287
- `import type { routes } from '../routes.ts'`,
289
+ `import { routes } from '../routes.ts'`,
288
290
  '',
289
- `export const home: BuildAction<'ANY', typeof routes.home> = {`,
290
- ' handler() {',
291
- ' let page = html`',
292
- ' <html lang="en">',
293
- ' <head>',
294
- ' <meta charset="utf-8" />',
295
- ' <meta name="viewport" content="width=device-width, initial-scale=1" />',
296
- ' <title>Home</title>',
297
- ' </head>',
298
- ' <body>',
299
- ' <h1>Home</h1>',
300
- ' <p>Update app/routes.ts and app/controllers/home to keep building your app.</p>',
301
- ' </body>',
302
- ' </html>',
303
- ' `',
304
- ' return createHtmlResponse(page)',
291
+ `export default createController(routes, {`,
292
+ ' actions: {',
293
+ ' home() {',
294
+ ' let page = html`',
295
+ ' <html lang="en">',
296
+ ' <head>',
297
+ ' <meta charset="utf-8" />',
298
+ ' <meta name="viewport" content="width=device-width, initial-scale=1" />',
299
+ ' <title>Home</title>',
300
+ ' </head>',
301
+ ' <body>',
302
+ ' <h1>Home</h1>',
303
+ ' <p>Update app/routes.ts and app/actions/controller to keep building your app.</p>',
304
+ ' </body>',
305
+ ' </html>',
306
+ ' `',
307
+ ' return createHtmlResponse(page)',
308
+ ' },',
305
309
  ' },',
306
- '}',
310
+ `})`,
307
311
  '',
308
312
  ].join('\n');
309
313
  }
@@ -312,10 +316,12 @@ function renderDefaultHomeAction(entryPath) {
312
316
  `import { renderToStream } from 'remix/ui/server'`,
313
317
  `import { createHtmlResponse } from 'remix/response/html'`,
314
318
  '',
315
- 'export const home = {',
316
- ' handler() {',
317
- ' let page = <HomePage />',
318
- ' return createHtmlResponse(renderToStream(page))',
319
+ 'export default {',
320
+ ' actions: {',
321
+ ' home() {',
322
+ ' let page = <HomePage />',
323
+ ' return createHtmlResponse(renderToStream(page))',
324
+ ' },',
319
325
  ' },',
320
326
  '}',
321
327
  '',
@@ -329,7 +335,7 @@ function renderDefaultHomeAction(entryPath) {
329
335
  ' </head>',
330
336
  ' <body>',
331
337
  ' <h1>Home</h1>',
332
- ' <p>Update app/routes.ts and app/controllers/home to keep building your app.</p>',
338
+ ' <p>Update app/routes.ts and app/actions/controller to keep building your app.</p>',
333
339
  ' </body>',
334
340
  ' </html>',
335
341
  ' )',
@@ -338,18 +344,20 @@ function renderDefaultHomeAction(entryPath) {
338
344
  ].join('\n');
339
345
  }
340
346
  return [
341
- `import type { BuildAction } from 'remix/fetch-router'`,
347
+ `import { createController } from 'remix/router'`,
342
348
  `import { renderToStream } from 'remix/ui/server'`,
343
349
  `import { createHtmlResponse } from 'remix/response/html'`,
344
350
  '',
345
- `import type { routes } from '../routes.ts'`,
351
+ `import { routes } from '../routes.ts'`,
346
352
  '',
347
- `export const home: BuildAction<'ANY', typeof routes.home> = {`,
348
- ' handler() {',
349
- ' let page = <HomePage />',
350
- ' return createHtmlResponse(renderToStream(page))',
353
+ `export default createController(routes, {`,
354
+ ' actions: {',
355
+ ' home() {',
356
+ ' let page = <HomePage />',
357
+ ' return createHtmlResponse(renderToStream(page))',
358
+ ' },',
351
359
  ' },',
352
- '}',
360
+ `})`,
353
361
  '',
354
362
  'function HomePage() {',
355
363
  ' return () => (',
@@ -361,7 +369,7 @@ function renderDefaultHomeAction(entryPath) {
361
369
  ' </head>',
362
370
  ' <body>',
363
371
  ' <h1>Home</h1>',
364
- ' <p>Update app/routes.ts and app/controllers/home to keep building your app.</p>',
372
+ ' <p>Update app/routes.ts and app/actions/controller to keep building your app.</p>',
365
373
  ' </body>',
366
374
  ' </html>',
367
375
  ' )',
@@ -1,7 +1,7 @@
1
- export type DoctorSuiteName = 'environment' | 'project' | 'controllers';
1
+ export type DoctorSuiteName = 'environment' | 'project' | 'actions';
2
2
  export type DoctorFindingSeverity = 'warn' | 'advice';
3
3
  export type DoctorSuiteStatus = 'ok' | 'issues' | 'skipped';
4
- export type DoctorFindingCode = 'project-root-not-found' | 'package-json-read-failed' | 'package-json-invalid' | 'node-engine-missing' | 'node-engine-unparseable' | 'node-version-unsupported' | 'remix-dependency-missing' | 'remix-install-missing' | 'routes-file-missing' | 'routes-export-missing' | 'route-map-invalid' | 'route-module-import-failed' | 'route-map-invalid-json' | 'route-map-loader-signal' | 'missing-owner' | 'wrong-owner-kind' | 'ambiguous-owner' | 'duplicate-owner-file' | 'incomplete-controller' | 'promotion-drift' | 'orphan-action' | 'orphan-controller' | 'orphan-route-directory';
4
+ export type DoctorFindingCode = 'project-root-not-found' | 'package-json-read-failed' | 'package-json-invalid' | 'node-engine-missing' | 'node-engine-unparseable' | 'node-version-unsupported' | 'remix-dependency-missing' | 'remix-install-missing' | 'routes-file-missing' | 'routes-export-missing' | 'route-map-invalid' | 'route-module-import-failed' | 'route-map-invalid-json' | 'route-map-loader-signal' | 'missing-owner' | 'duplicate-owner-file' | 'incomplete-controller' | 'orphan-controller' | 'orphan-route-directory';
5
5
  export type DoctorFixKind = 'create-directory' | 'create-file' | 'update-file';
6
6
  export interface DoctorFinding {
7
7
  actualPath?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/doctor/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,aAAa,GAAG,SAAS,GAAG,aAAa,CAAA;AACvE,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,QAAQ,CAAA;AACrD,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,QAAQ,GAAG,SAAS,CAAA;AAE3D,MAAM,MAAM,iBAAiB,GACzB,wBAAwB,GACxB,0BAA0B,GAC1B,sBAAsB,GACtB,qBAAqB,GACrB,yBAAyB,GACzB,0BAA0B,GAC1B,0BAA0B,GAC1B,uBAAuB,GACvB,qBAAqB,GACrB,uBAAuB,GACvB,mBAAmB,GACnB,4BAA4B,GAC5B,wBAAwB,GACxB,yBAAyB,GACzB,eAAe,GACf,kBAAkB,GAClB,iBAAiB,GACjB,sBAAsB,GACtB,uBAAuB,GACvB,iBAAiB,GACjB,eAAe,GACf,mBAAmB,GACnB,wBAAwB,CAAA;AAE5B,MAAM,MAAM,aAAa,GAAG,kBAAkB,GAAG,aAAa,GAAG,aAAa,CAAA;AAE9E,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,iBAAiB,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,qBAAqB,CAAA;IAC/B,KAAK,EAAE,eAAe,CAAA;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,iBAAiB,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,aAAa,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,eAAe,CAAA;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,iBAAiB,CAAA;IACvB,IAAI,EAAE,aAAa,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,eAAe,CAAA;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,YAAY,CAAC,EAAE,gBAAgB,EAAE,CAAA;IACjC,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,IAAI,EAAE,eAAe,CAAA;IACrB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,iBAAiB,CAAA;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,CAAC,EAAE,gBAAgB,EAAE,CAAA;IACjC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,iBAAiB,CAAC,EAAE,aAAa,EAAE,CAAA;IACnC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,iBAAiB,EAAE,CAAA;CAC5B;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,eAAe,EACrB,QAAQ,EAAE,aAAa,EAAE,GACxB,iBAAiB,CAMnB;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAOjG"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/doctor/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,aAAa,GAAG,SAAS,GAAG,SAAS,CAAA;AACnE,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,QAAQ,CAAA;AACrD,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,QAAQ,GAAG,SAAS,CAAA;AAE3D,MAAM,MAAM,iBAAiB,GACzB,wBAAwB,GACxB,0BAA0B,GAC1B,sBAAsB,GACtB,qBAAqB,GACrB,yBAAyB,GACzB,0BAA0B,GAC1B,0BAA0B,GAC1B,uBAAuB,GACvB,qBAAqB,GACrB,uBAAuB,GACvB,mBAAmB,GACnB,4BAA4B,GAC5B,wBAAwB,GACxB,yBAAyB,GACzB,eAAe,GACf,sBAAsB,GACtB,uBAAuB,GACvB,mBAAmB,GACnB,wBAAwB,CAAA;AAE5B,MAAM,MAAM,aAAa,GAAG,kBAAkB,GAAG,aAAa,GAAG,aAAa,CAAA;AAE9E,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,iBAAiB,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,qBAAqB,CAAA;IAC/B,KAAK,EAAE,eAAe,CAAA;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,iBAAiB,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,aAAa,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,eAAe,CAAA;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,iBAAiB,CAAA;IACvB,IAAI,EAAE,aAAa,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,eAAe,CAAA;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,YAAY,CAAC,EAAE,gBAAgB,EAAE,CAAA;IACjC,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,IAAI,EAAE,eAAe,CAAA;IACrB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,iBAAiB,CAAA;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,CAAC,EAAE,gBAAgB,EAAE,CAAA;IACjC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,iBAAiB,CAAC,EAAE,aAAa,EAAE,CAAA;IACnC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,iBAAiB,EAAE,CAAA;CAC5B;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,eAAe,EACrB,QAAQ,EAAE,aAAa,EAAE,GACxB,iBAAiB,CAMnB;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAOjG"}
@@ -125,11 +125,6 @@ export declare const CLI_ERROR_DEFINITIONS: {
125
125
  title: string;
126
126
  fix: string;
127
127
  };
128
- unknownSkillsCommand: {
129
- code: string;
130
- title: string;
131
- fix: string;
132
- };
133
128
  };
134
129
  export declare class CliError extends Error {
135
130
  code: string;
@@ -165,7 +160,6 @@ export declare function unknownArgument(argument: string): UsageError;
165
160
  export declare function unknownCommand(command: string): UsageError;
166
161
  export declare function unknownCompletionShell(shell: string): UsageError;
167
162
  export declare function unknownHelpTopic(topic: string): UsageError;
168
- export declare function unknownSkillsCommand(command: string): UsageError;
169
163
  export declare function unexpectedExtraArgument(argument: string): UsageError;
170
164
  export declare function renderCliError(error: unknown, options?: {
171
165
  helpText?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"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"}
@@ -109,11 +109,6 @@ export const CLI_ERROR_DEFINITIONS = {
109
109
  title: 'Unknown help topic',
110
110
  fix: 'Run `remix help` to see available commands and help topics.',
111
111
  },
112
- unknownSkillsCommand: {
113
- code: 'RMX_UNKNOWN_SKILLS_COMMAND',
114
- title: 'Unknown skills command',
115
- fix: 'Run `remix skills --help` to see available skills commands.',
116
- },
117
112
  };
118
113
  export class CliError extends Error {
119
114
  code;
@@ -269,12 +264,6 @@ export function unknownHelpTopic(topic) {
269
264
  message: `Unknown help topic: ${topic}`,
270
265
  });
271
266
  }
272
- export function unknownSkillsCommand(command) {
273
- return createUsageError(CLI_ERROR_DEFINITIONS.unknownSkillsCommand, {
274
- context: { command },
275
- message: `Unknown skills command: ${command}`,
276
- });
277
- }
278
267
  export function unexpectedExtraArgument(argument) {
279
268
  return createUsageError(CLI_ERROR_DEFINITIONS.unexpectedExtraArgument, {
280
269
  context: { argument },
@@ -30,7 +30,7 @@ async function loadRawRouteTree(routesFile) {
30
30
  if (!('routes' in routeModule)) {
31
31
  throw new Error(`Route module ${routesFile} must export a named "routes" value.`);
32
32
  }
33
- return normalizeRouteGroup(Reflect.get(routeModule, 'routes'), [], new Map());
33
+ return normalizeRouteGroup(routeModule.routes, [], new Map());
34
34
  }
35
35
  function normalizeRouteGroup(value, parentSegments, seen) {
36
36
  if (!isPlainObject(value)) {
@@ -47,14 +47,15 @@ function normalizeRouteGroup(value, parentSegments, seen) {
47
47
  return Object.entries(value).map(([key, entryValue]) => {
48
48
  let nameSegments = [...parentSegments, key];
49
49
  let name = nameSegments.join('.');
50
- if (isRouteLeaf(entryValue)) {
50
+ let routeLeaf = readRouteLeaf(entryValue);
51
+ if (routeLeaf !== undefined) {
51
52
  return {
52
53
  children: [],
53
54
  key,
54
55
  kind: 'route',
55
- method: entryValue.method,
56
+ method: routeLeaf.method,
56
57
  name,
57
- pattern: entryValue.pattern.source,
58
+ pattern: routeLeaf.pattern,
58
59
  };
59
60
  }
60
61
  if (isPlainObject(entryValue)) {
@@ -72,13 +73,20 @@ function normalizeRouteGroup(value, parentSegments, seen) {
72
73
  seen.delete(value);
73
74
  }
74
75
  }
75
- function isRouteLeaf(value) {
76
+ function readRouteLeaf(value) {
77
+ if (typeof value !== 'object' || value == null)
78
+ return undefined;
79
+ let method = Reflect.get(value, 'method');
80
+ let pattern = Reflect.get(value, 'pattern');
81
+ if (typeof method !== 'string' || !hasToString(pattern))
82
+ return undefined;
83
+ return { method, pattern: pattern.toString() };
84
+ }
85
+ function hasToString(value) {
76
86
  return (typeof value === 'object' &&
77
87
  value != null &&
78
- typeof Reflect.get(value, 'method') === 'string' &&
79
- typeof Reflect.get(value, 'pattern') === 'object' &&
80
- Reflect.get(value, 'pattern') != null &&
81
- typeof Reflect.get(Reflect.get(value, 'pattern'), 'source') === 'string');
88
+ 'toString' in value &&
89
+ typeof value.toString === 'function');
82
90
  }
83
91
  function isPlainObject(value) {
84
92
  if (typeof value !== 'object' || value == null) {
@@ -1,4 +1,4 @@
1
- export type RouteOwnerKind = 'action' | 'controller';
1
+ export type RouteOwnerKind = 'controller' | 'directory';
2
2
  export type RouteTreeNodeKind = 'group' | 'route';
3
3
  export interface RouteTreeOwner {
4
4
  exists: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"route-map.d.ts","sourceRoot":"","sources":["../../src/lib/route-map.ts"],"names":[],"mappings":"AAeA,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,YAAY,CAAA;AACpD,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,OAAO,CAAA;AAEjD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,cAAc,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,iBAAiB,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,cAAc,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,aAAa,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,gBAAgB,EAAE,CAAA;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,gBAAgB,EAAE,CAAA;IAC5B,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,iBAAiB,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,wBAAsB,YAAY,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,cAAc,CAAC,CAUvF;AAED,wBAAsB,iBAAiB,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAGjG;AAED,wBAAsB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAShG"}
1
+ {"version":3,"file":"route-map.d.ts","sourceRoot":"","sources":["../../src/lib/route-map.ts"],"names":[],"mappings":"AAqBA,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,WAAW,CAAA;AACvD,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,OAAO,CAAA;AAEjD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,cAAc,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,iBAAiB,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,cAAc,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,aAAa,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,gBAAgB,EAAE,CAAA;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,gBAAgB,EAAE,CAAA;IAC5B,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,iBAAiB,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,wBAAsB,YAAY,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,cAAc,CAAC,CAUvF;AAED,wBAAsB,iBAAiB,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAGjG;AAED,wBAAsB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAShG"}