@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.
- package/README.md +0 -3
- package/dist/lib/bootstrap-project.d.ts.map +1 -1
- package/dist/lib/bootstrap-project.js +32 -9
- package/dist/lib/cli.d.ts +29 -0
- package/dist/lib/cli.d.ts.map +1 -1
- package/dist/lib/cli.js +33 -14
- package/dist/lib/commands/completion.d.ts.map +1 -1
- package/dist/lib/commands/completion.js +5 -1
- package/dist/lib/commands/doctor.js +18 -18
- package/dist/lib/commands/help.d.ts.map +1 -1
- package/dist/lib/commands/help.js +9 -33
- package/dist/lib/commands/routes.js +3 -3
- package/dist/lib/commands/test.d.ts +1 -1
- package/dist/lib/commands/test.d.ts.map +1 -1
- package/dist/lib/commands/test.js +8 -4
- package/dist/lib/completion.d.ts.map +1 -1
- package/dist/lib/completion.js +4 -106
- package/dist/lib/controller-files.d.ts +0 -1
- package/dist/lib/controller-files.d.ts.map +1 -1
- package/dist/lib/controller-files.js +3 -5
- package/dist/lib/controller-ownership.d.ts +9 -9
- package/dist/lib/controller-ownership.d.ts.map +1 -1
- package/dist/lib/controller-ownership.js +56 -91
- package/dist/lib/doctor/controller-findings.d.ts +1 -1
- package/dist/lib/doctor/controller-findings.d.ts.map +1 -1
- package/dist/lib/doctor/controller-findings.js +15 -87
- package/dist/lib/doctor/controller-fix-plans.d.ts.map +1 -1
- package/dist/lib/doctor/controller-fix-plans.js +13 -24
- package/dist/lib/doctor/controller-placeholders.d.ts +2 -3
- package/dist/lib/doctor/controller-placeholders.d.ts.map +1 -1
- package/dist/lib/doctor/controller-placeholders.js +18 -149
- package/dist/lib/doctor/controllers.js +1 -1
- package/dist/lib/doctor/project.js +60 -52
- package/dist/lib/doctor/types.d.ts +2 -2
- package/dist/lib/doctor/types.d.ts.map +1 -1
- package/dist/lib/errors.d.ts +0 -6
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +0 -11
- package/dist/lib/load-route-map-worker.js +17 -9
- package/dist/lib/route-map.d.ts +1 -1
- package/dist/lib/route-map.d.ts.map +1 -1
- package/dist/lib/route-map.js +29 -17
- package/package.json +4 -5
- package/src/lib/bootstrap-project.ts +39 -13
- package/src/lib/cli.ts +46 -15
- package/src/lib/commands/completion.ts +6 -1
- package/src/lib/commands/doctor.ts +18 -21
- package/src/lib/commands/help.ts +9 -43
- package/src/lib/commands/routes.ts +3 -3
- package/src/lib/commands/test.ts +10 -4
- package/src/lib/completion.ts +4 -151
- package/src/lib/controller-files.ts +4 -8
- package/src/lib/controller-ownership.ts +78 -141
- package/src/lib/doctor/controller-findings.ts +20 -97
- package/src/lib/doctor/controller-fix-plans.ts +13 -29
- package/src/lib/doctor/controller-placeholders.ts +17 -189
- package/src/lib/doctor/controllers.ts +1 -1
- package/src/lib/doctor/project.ts +60 -52
- package/src/lib/doctor/types.ts +1 -5
- package/src/lib/errors.ts +0 -12
- package/src/lib/load-route-map-worker.ts +19 -10
- package/src/lib/route-map.ts +61 -16
- package/template/.agents/skills/remix/SKILL.md +588 -0
- package/template/.agents/skills/remix/references/animate-elements.md +195 -0
- package/template/.agents/skills/remix/references/assets-and-browser-modules.md +130 -0
- package/template/.agents/skills/remix/references/auth-and-sessions.md +443 -0
- package/template/.agents/skills/remix/references/component-model.md +282 -0
- package/template/.agents/skills/remix/references/create-mixins.md +158 -0
- package/template/.agents/skills/remix/references/data-and-validation.md +379 -0
- package/template/.agents/skills/remix/references/hydration-frames-navigation.md +297 -0
- package/template/.agents/skills/remix/references/middleware-and-server.md +233 -0
- package/template/.agents/skills/remix/references/mixins-styling-events.md +213 -0
- package/template/.agents/skills/remix/references/routing-and-controllers.md +391 -0
- package/template/.agents/skills/remix/references/testing-patterns.md +172 -0
- package/{bootstrap → template}/AGENTS.md +13 -8
- package/template/README.md +29 -0
- package/template/app/actions/controller.tsx +18 -0
- package/template/app/assets/entry.ts +8 -0
- package/template/app/assets/prompt-button.tsx +163 -0
- package/template/app/assets.ts +20 -0
- package/template/app/middleware/render.tsx +43 -0
- package/template/app/router.ts +20 -0
- package/template/app/routes.ts +6 -0
- package/template/app/ui/document.tsx +33 -0
- package/template/app/ui/scaffold-home-page.tsx +527 -0
- package/template/gitignore +4 -0
- package/{bootstrap → template}/package.json +5 -6
- package/template/public/favicon.svg +11 -0
- package/{bootstrap → template}/server.ts +4 -5
- package/{bootstrap → template}/tsconfig.json +3 -3
- package/bootstrap/README.md +0 -27
- package/bootstrap/app/controllers/auth.tsx +0 -21
- package/bootstrap/app/controllers/home.tsx +0 -26
- package/bootstrap/app/router.ts +0 -10
- package/bootstrap/app/routes.ts +0 -6
- package/bootstrap/app/ui/document.tsx +0 -21
- package/bootstrap/app/ui/layout.tsx +0 -22
- package/bootstrap/app/utils/render.tsx +0 -7
- package/dist/lib/commands/skills.d.ts +0 -6
- package/dist/lib/commands/skills.d.ts.map +0 -1
- package/dist/lib/commands/skills.js +0 -222
- package/dist/lib/skills-cache.d.ts +0 -19
- package/dist/lib/skills-cache.d.ts.map +0 -1
- package/dist/lib/skills-cache.js +0 -89
- package/dist/lib/skills.d.ts +0 -30
- package/dist/lib/skills.d.ts.map +0 -1
- package/dist/lib/skills.js +0 -441
- package/src/lib/commands/skills.ts +0 -306
- package/src/lib/skills-cache.ts +0 -140
- package/src/lib/skills.ts +0 -706
|
@@ -62,7 +62,7 @@ export async function checkProject(projectRoot: string): Promise<ProjectDoctorRe
|
|
|
62
62
|
export async function getProjectFixPlans(projectRoot: string): Promise<DoctorFixPlan[]> {
|
|
63
63
|
let routesFile = path.join(projectRoot, 'app', 'routes.ts')
|
|
64
64
|
let homeActionPath = normalizeRelativePath(
|
|
65
|
-
path.join('app', '
|
|
65
|
+
path.join('app', 'actions', `controller${await inferHomeOwnerExtension(projectRoot)}`),
|
|
66
66
|
)
|
|
67
67
|
|
|
68
68
|
if (await pathExists(routesFile)) {
|
|
@@ -225,8 +225,8 @@ function hasOnlyWhitespaceAndComments(source: string): boolean {
|
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
async function inferHomeOwnerExtension(projectRoot: string): Promise<OwnerFileExtension> {
|
|
228
|
-
let
|
|
229
|
-
let extensions = await collectOwnerExtensions(
|
|
228
|
+
let actionsDir = path.join(projectRoot, 'app', 'actions')
|
|
229
|
+
let extensions = await collectOwnerExtensions(actionsDir)
|
|
230
230
|
|
|
231
231
|
if (extensions.length > 0) {
|
|
232
232
|
return getMostCommonExtension(extensions)
|
|
@@ -298,7 +298,7 @@ function getMostCommonExtension(extensions: OwnerFileExtension[]): OwnerFileExte
|
|
|
298
298
|
|
|
299
299
|
function renderDefaultRoutesFile(): string {
|
|
300
300
|
return [
|
|
301
|
-
`import { route } from 'remix/
|
|
301
|
+
`import { route } from 'remix/routes'`,
|
|
302
302
|
'',
|
|
303
303
|
'export const routes = route({',
|
|
304
304
|
` home: '/',`,
|
|
@@ -318,22 +318,24 @@ function renderDefaultHomeAction(entryPath: string): string {
|
|
|
318
318
|
`import { html } from 'remix/html-template'`,
|
|
319
319
|
`import { createHtmlResponse } from 'remix/response/html'`,
|
|
320
320
|
'',
|
|
321
|
-
'export
|
|
322
|
-
'
|
|
323
|
-
'
|
|
324
|
-
'
|
|
325
|
-
' <
|
|
326
|
-
' <
|
|
327
|
-
'
|
|
328
|
-
'
|
|
329
|
-
'
|
|
330
|
-
'
|
|
331
|
-
' <
|
|
332
|
-
'
|
|
333
|
-
'
|
|
334
|
-
'
|
|
335
|
-
'
|
|
336
|
-
'
|
|
321
|
+
'export default {',
|
|
322
|
+
' actions: {',
|
|
323
|
+
' home() {',
|
|
324
|
+
' let page = html`',
|
|
325
|
+
' <html lang="en">',
|
|
326
|
+
' <head>',
|
|
327
|
+
' <meta charset="utf-8" />',
|
|
328
|
+
' <meta name="viewport" content="width=device-width, initial-scale=1" />',
|
|
329
|
+
' <title>Home</title>',
|
|
330
|
+
' </head>',
|
|
331
|
+
' <body>',
|
|
332
|
+
' <h1>Home</h1>',
|
|
333
|
+
' <p>Update app/routes.ts and app/actions/controller to keep building your app.</p>',
|
|
334
|
+
' </body>',
|
|
335
|
+
' </html>',
|
|
336
|
+
' `',
|
|
337
|
+
' return createHtmlResponse(page)',
|
|
338
|
+
' },',
|
|
337
339
|
' },',
|
|
338
340
|
'}',
|
|
339
341
|
'',
|
|
@@ -342,30 +344,32 @@ function renderDefaultHomeAction(entryPath: string): string {
|
|
|
342
344
|
|
|
343
345
|
if (extension === '.ts') {
|
|
344
346
|
return [
|
|
345
|
-
`import
|
|
347
|
+
`import { createController } from 'remix/router'`,
|
|
346
348
|
`import { html } from 'remix/html-template'`,
|
|
347
349
|
`import { createHtmlResponse } from 'remix/response/html'`,
|
|
348
350
|
'',
|
|
349
|
-
`import
|
|
351
|
+
`import { routes } from '../routes.ts'`,
|
|
350
352
|
'',
|
|
351
|
-
`export
|
|
352
|
-
'
|
|
353
|
-
'
|
|
354
|
-
'
|
|
355
|
-
' <
|
|
356
|
-
' <
|
|
357
|
-
'
|
|
358
|
-
'
|
|
359
|
-
'
|
|
360
|
-
'
|
|
361
|
-
' <
|
|
362
|
-
'
|
|
363
|
-
'
|
|
364
|
-
'
|
|
365
|
-
'
|
|
366
|
-
'
|
|
353
|
+
`export default createController(routes, {`,
|
|
354
|
+
' actions: {',
|
|
355
|
+
' home() {',
|
|
356
|
+
' let page = html`',
|
|
357
|
+
' <html lang="en">',
|
|
358
|
+
' <head>',
|
|
359
|
+
' <meta charset="utf-8" />',
|
|
360
|
+
' <meta name="viewport" content="width=device-width, initial-scale=1" />',
|
|
361
|
+
' <title>Home</title>',
|
|
362
|
+
' </head>',
|
|
363
|
+
' <body>',
|
|
364
|
+
' <h1>Home</h1>',
|
|
365
|
+
' <p>Update app/routes.ts and app/actions/controller to keep building your app.</p>',
|
|
366
|
+
' </body>',
|
|
367
|
+
' </html>',
|
|
368
|
+
' `',
|
|
369
|
+
' return createHtmlResponse(page)',
|
|
370
|
+
' },',
|
|
367
371
|
' },',
|
|
368
|
-
|
|
372
|
+
`})`,
|
|
369
373
|
'',
|
|
370
374
|
].join('\n')
|
|
371
375
|
}
|
|
@@ -375,10 +379,12 @@ function renderDefaultHomeAction(entryPath: string): string {
|
|
|
375
379
|
`import { renderToStream } from 'remix/ui/server'`,
|
|
376
380
|
`import { createHtmlResponse } from 'remix/response/html'`,
|
|
377
381
|
'',
|
|
378
|
-
'export
|
|
379
|
-
'
|
|
380
|
-
'
|
|
381
|
-
'
|
|
382
|
+
'export default {',
|
|
383
|
+
' actions: {',
|
|
384
|
+
' home() {',
|
|
385
|
+
' let page = <HomePage />',
|
|
386
|
+
' return createHtmlResponse(renderToStream(page))',
|
|
387
|
+
' },',
|
|
382
388
|
' },',
|
|
383
389
|
'}',
|
|
384
390
|
'',
|
|
@@ -392,7 +398,7 @@ function renderDefaultHomeAction(entryPath: string): string {
|
|
|
392
398
|
' </head>',
|
|
393
399
|
' <body>',
|
|
394
400
|
' <h1>Home</h1>',
|
|
395
|
-
' <p>Update app/routes.ts and app/
|
|
401
|
+
' <p>Update app/routes.ts and app/actions/controller to keep building your app.</p>',
|
|
396
402
|
' </body>',
|
|
397
403
|
' </html>',
|
|
398
404
|
' )',
|
|
@@ -402,18 +408,20 @@ function renderDefaultHomeAction(entryPath: string): string {
|
|
|
402
408
|
}
|
|
403
409
|
|
|
404
410
|
return [
|
|
405
|
-
`import
|
|
411
|
+
`import { createController } from 'remix/router'`,
|
|
406
412
|
`import { renderToStream } from 'remix/ui/server'`,
|
|
407
413
|
`import { createHtmlResponse } from 'remix/response/html'`,
|
|
408
414
|
'',
|
|
409
|
-
`import
|
|
415
|
+
`import { routes } from '../routes.ts'`,
|
|
410
416
|
'',
|
|
411
|
-
`export
|
|
412
|
-
'
|
|
413
|
-
'
|
|
414
|
-
'
|
|
417
|
+
`export default createController(routes, {`,
|
|
418
|
+
' actions: {',
|
|
419
|
+
' home() {',
|
|
420
|
+
' let page = <HomePage />',
|
|
421
|
+
' return createHtmlResponse(renderToStream(page))',
|
|
422
|
+
' },',
|
|
415
423
|
' },',
|
|
416
|
-
|
|
424
|
+
`})`,
|
|
417
425
|
'',
|
|
418
426
|
'function HomePage() {',
|
|
419
427
|
' return () => (',
|
|
@@ -425,7 +433,7 @@ function renderDefaultHomeAction(entryPath: string): string {
|
|
|
425
433
|
' </head>',
|
|
426
434
|
' <body>',
|
|
427
435
|
' <h1>Home</h1>',
|
|
428
|
-
' <p>Update app/routes.ts and app/
|
|
436
|
+
' <p>Update app/routes.ts and app/actions/controller to keep building your app.</p>',
|
|
429
437
|
' </body>',
|
|
430
438
|
' </html>',
|
|
431
439
|
' )',
|
package/src/lib/doctor/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type DoctorSuiteName = 'environment' | 'project' | '
|
|
1
|
+
export type DoctorSuiteName = 'environment' | 'project' | 'actions'
|
|
2
2
|
export type DoctorFindingSeverity = 'warn' | 'advice'
|
|
3
3
|
export type DoctorSuiteStatus = 'ok' | 'issues' | 'skipped'
|
|
4
4
|
|
|
@@ -18,12 +18,8 @@ export type DoctorFindingCode =
|
|
|
18
18
|
| 'route-map-invalid-json'
|
|
19
19
|
| 'route-map-loader-signal'
|
|
20
20
|
| 'missing-owner'
|
|
21
|
-
| 'wrong-owner-kind'
|
|
22
|
-
| 'ambiguous-owner'
|
|
23
21
|
| 'duplicate-owner-file'
|
|
24
22
|
| 'incomplete-controller'
|
|
25
|
-
| 'promotion-drift'
|
|
26
|
-
| 'orphan-action'
|
|
27
23
|
| 'orphan-controller'
|
|
28
24
|
| 'orphan-route-directory'
|
|
29
25
|
|
package/src/lib/errors.ts
CHANGED
|
@@ -133,11 +133,6 @@ export const CLI_ERROR_DEFINITIONS = {
|
|
|
133
133
|
title: 'Unknown help topic',
|
|
134
134
|
fix: 'Run `remix help` to see available commands and help topics.',
|
|
135
135
|
},
|
|
136
|
-
unknownSkillsCommand: {
|
|
137
|
-
code: 'RMX_UNKNOWN_SKILLS_COMMAND',
|
|
138
|
-
title: 'Unknown skills command',
|
|
139
|
-
fix: 'Run `remix skills --help` to see available skills commands.',
|
|
140
|
-
},
|
|
141
136
|
} satisfies Record<string, CliErrorDefinition>
|
|
142
137
|
|
|
143
138
|
export class CliError extends Error {
|
|
@@ -321,13 +316,6 @@ export function unknownHelpTopic(topic: string): UsageError {
|
|
|
321
316
|
})
|
|
322
317
|
}
|
|
323
318
|
|
|
324
|
-
export function unknownSkillsCommand(command: string): UsageError {
|
|
325
|
-
return createUsageError(CLI_ERROR_DEFINITIONS.unknownSkillsCommand, {
|
|
326
|
-
context: { command },
|
|
327
|
-
message: `Unknown skills command: ${command}`,
|
|
328
|
-
})
|
|
329
|
-
}
|
|
330
|
-
|
|
331
319
|
export function unexpectedExtraArgument(argument: string): UsageError {
|
|
332
320
|
return createUsageError(CLI_ERROR_DEFINITIONS.unexpectedExtraArgument, {
|
|
333
321
|
context: { argument },
|
|
@@ -24,13 +24,13 @@ async function run(): Promise<void> {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
async function loadRawRouteTree(routesFile: string): Promise<RawRouteTreeNode[]> {
|
|
27
|
-
let routeModule = await import(pathToFileURL(routesFile).href)
|
|
27
|
+
let routeModule: object = await import(pathToFileURL(routesFile).href)
|
|
28
28
|
|
|
29
29
|
if (!('routes' in routeModule)) {
|
|
30
30
|
throw new Error(`Route module ${routesFile} must export a named "routes" value.`)
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
return normalizeRouteGroup(
|
|
33
|
+
return normalizeRouteGroup(routeModule.routes, [], new Map())
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
function normalizeRouteGroup(
|
|
@@ -55,15 +55,16 @@ function normalizeRouteGroup(
|
|
|
55
55
|
return Object.entries(value).map(([key, entryValue]) => {
|
|
56
56
|
let nameSegments = [...parentSegments, key]
|
|
57
57
|
let name = nameSegments.join('.')
|
|
58
|
+
let routeLeaf = readRouteLeaf(entryValue)
|
|
58
59
|
|
|
59
|
-
if (
|
|
60
|
+
if (routeLeaf !== undefined) {
|
|
60
61
|
return {
|
|
61
62
|
children: [],
|
|
62
63
|
key,
|
|
63
64
|
kind: 'route',
|
|
64
|
-
method:
|
|
65
|
+
method: routeLeaf.method,
|
|
65
66
|
name,
|
|
66
|
-
pattern:
|
|
67
|
+
pattern: routeLeaf.pattern,
|
|
67
68
|
} satisfies RawRouteTreeNode
|
|
68
69
|
}
|
|
69
70
|
|
|
@@ -85,14 +86,22 @@ function normalizeRouteGroup(
|
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
function
|
|
89
|
+
function readRouteLeaf(value: unknown): { method: string; pattern: string } | undefined {
|
|
90
|
+
if (typeof value !== 'object' || value == null) return undefined
|
|
91
|
+
|
|
92
|
+
let method = Reflect.get(value, 'method')
|
|
93
|
+
let pattern = Reflect.get(value, 'pattern')
|
|
94
|
+
if (typeof method !== 'string' || !hasToString(pattern)) return undefined
|
|
95
|
+
|
|
96
|
+
return { method, pattern: pattern.toString() }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function hasToString(value: unknown): value is { toString(): string } {
|
|
89
100
|
return (
|
|
90
101
|
typeof value === 'object' &&
|
|
91
102
|
value != null &&
|
|
92
|
-
|
|
93
|
-
typeof
|
|
94
|
-
Reflect.get(value, 'pattern') != null &&
|
|
95
|
-
typeof Reflect.get(Reflect.get(value, 'pattern'), 'source') === 'string'
|
|
103
|
+
'toString' in value &&
|
|
104
|
+
typeof value.toString === 'function'
|
|
96
105
|
)
|
|
97
106
|
}
|
|
98
107
|
|
package/src/lib/route-map.ts
CHANGED
|
@@ -4,7 +4,13 @@ import * as process from 'node:process'
|
|
|
4
4
|
import { spawn } from 'node:child_process'
|
|
5
5
|
import { fileURLToPath } from 'node:url'
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
ROOT_ROUTE_NAME,
|
|
9
|
+
inspectControllerOwnership,
|
|
10
|
+
type ControllerOwnership,
|
|
11
|
+
type OwnedSubtree,
|
|
12
|
+
type RouteDirectoryPlan,
|
|
13
|
+
} from './controller-ownership.ts'
|
|
8
14
|
import {
|
|
9
15
|
routeMapLoaderFailed,
|
|
10
16
|
routeMapLoaderInvalidJson,
|
|
@@ -13,7 +19,7 @@ import {
|
|
|
13
19
|
routesFileNotFound,
|
|
14
20
|
} from './errors.ts'
|
|
15
21
|
|
|
16
|
-
export type RouteOwnerKind = '
|
|
22
|
+
export type RouteOwnerKind = 'controller' | 'directory'
|
|
17
23
|
export type RouteTreeNodeKind = 'group' | 'route'
|
|
18
24
|
|
|
19
25
|
export interface RouteTreeOwner {
|
|
@@ -56,7 +62,7 @@ export interface RawRouteTreeNode {
|
|
|
56
62
|
export async function loadRouteMap(cwd: string = process.cwd()): Promise<LoadedRouteMap> {
|
|
57
63
|
let manifest = await loadRouteManifest(cwd)
|
|
58
64
|
let ownership = await inspectControllerOwnership(manifest.appRoot, manifest.tree)
|
|
59
|
-
let tree = decorateRouteTree(manifest.tree, ownership
|
|
65
|
+
let tree = decorateRouteTree(manifest.tree, ownership)
|
|
60
66
|
|
|
61
67
|
return {
|
|
62
68
|
appRoot: manifest.appRoot,
|
|
@@ -137,28 +143,51 @@ async function loadRawRouteMap(appRoot: string, routesFile: string): Promise<Raw
|
|
|
137
143
|
|
|
138
144
|
function decorateRouteTree(
|
|
139
145
|
rawTree: RawRouteTreeNode[],
|
|
140
|
-
|
|
141
|
-
parentSegments: string[] = [],
|
|
146
|
+
ownership: ControllerOwnership,
|
|
142
147
|
): RouteTreeNode[] {
|
|
143
|
-
let subtreesByRouteName = new Map(
|
|
148
|
+
let subtreesByRouteName = new Map(
|
|
149
|
+
ownership.subtrees.map((subtree) => [subtree.routeName, subtree]),
|
|
150
|
+
)
|
|
151
|
+
let directoriesByRouteName = new Map(
|
|
152
|
+
ownership.routeDirectories.map((directory) => [directory.routeName, directory]),
|
|
153
|
+
)
|
|
144
154
|
|
|
145
|
-
return decorateRouteTreeWithLookup(
|
|
155
|
+
return decorateRouteTreeWithLookup(
|
|
156
|
+
rawTree,
|
|
157
|
+
subtreesByRouteName,
|
|
158
|
+
directoriesByRouteName,
|
|
159
|
+
ownership.scan.routeDirectoryPaths,
|
|
160
|
+
)
|
|
146
161
|
}
|
|
147
162
|
|
|
148
163
|
function decorateRouteTreeWithLookup(
|
|
149
164
|
rawTree: RawRouteTreeNode[],
|
|
150
165
|
subtreesByRouteName: Map<string, OwnedSubtree>,
|
|
166
|
+
directoriesByRouteName: Map<string, RouteDirectoryPlan>,
|
|
167
|
+
actualRouteDirectories: Set<string>,
|
|
151
168
|
parentSegments: string[] = [],
|
|
152
169
|
): RouteTreeNode[] {
|
|
153
170
|
return rawTree.map((rawNode) => {
|
|
154
|
-
let owner = getRouteOwner(
|
|
171
|
+
let owner = getRouteOwner(
|
|
172
|
+
rawNode,
|
|
173
|
+
parentSegments,
|
|
174
|
+
subtreesByRouteName,
|
|
175
|
+
directoriesByRouteName,
|
|
176
|
+
actualRouteDirectories,
|
|
177
|
+
)
|
|
155
178
|
let nextParentSegments =
|
|
156
179
|
rawNode.kind === 'group' ? [...parentSegments, rawNode.key] : parentSegments
|
|
157
180
|
|
|
158
181
|
return {
|
|
159
182
|
children:
|
|
160
183
|
rawNode.kind === 'group'
|
|
161
|
-
? decorateRouteTreeWithLookup(
|
|
184
|
+
? decorateRouteTreeWithLookup(
|
|
185
|
+
rawNode.children,
|
|
186
|
+
subtreesByRouteName,
|
|
187
|
+
directoriesByRouteName,
|
|
188
|
+
actualRouteDirectories,
|
|
189
|
+
nextParentSegments,
|
|
190
|
+
)
|
|
162
191
|
: [],
|
|
163
192
|
key: rawNode.key,
|
|
164
193
|
kind: rawNode.kind,
|
|
@@ -174,24 +203,40 @@ function getRouteOwner(
|
|
|
174
203
|
rawNode: RawRouteTreeNode,
|
|
175
204
|
parentSegments: string[],
|
|
176
205
|
subtreesByRouteName: Map<string, OwnedSubtree>,
|
|
206
|
+
directoriesByRouteName: Map<string, RouteDirectoryPlan>,
|
|
207
|
+
actualRouteDirectories: Set<string>,
|
|
177
208
|
): RouteTreeOwner {
|
|
178
209
|
let ownerRouteName =
|
|
179
210
|
rawNode.kind === 'group'
|
|
180
211
|
? rawNode.name
|
|
181
212
|
: parentSegments.length === 0
|
|
182
|
-
?
|
|
213
|
+
? ROOT_ROUTE_NAME
|
|
183
214
|
: parentSegments.join('.')
|
|
184
215
|
let subtree = subtreesByRouteName.get(ownerRouteName)
|
|
185
216
|
|
|
186
|
-
if (subtree
|
|
187
|
-
|
|
217
|
+
if (subtree != null) {
|
|
218
|
+
return {
|
|
219
|
+
exists: subtree.actualEntryPath != null,
|
|
220
|
+
kind: 'controller',
|
|
221
|
+
path: subtree.actualEntryPath ?? subtree.entryDisplayPath,
|
|
222
|
+
}
|
|
188
223
|
}
|
|
189
224
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
225
|
+
if (rawNode.kind === 'group') {
|
|
226
|
+
let directory = directoriesByRouteName.get(rawNode.name)
|
|
227
|
+
|
|
228
|
+
if (directory == null) {
|
|
229
|
+
throw routeOwnerPlanUnresolved(rawNode.name)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
exists: actualRouteDirectories.has(directory.directoryPath),
|
|
234
|
+
kind: 'directory',
|
|
235
|
+
path: directory.directoryPath,
|
|
236
|
+
}
|
|
194
237
|
}
|
|
238
|
+
|
|
239
|
+
throw routeOwnerPlanUnresolved(rawNode.name)
|
|
195
240
|
}
|
|
196
241
|
|
|
197
242
|
function assertRawRouteTree(value: unknown): RawRouteTreeNode[] {
|