@remix-run/cli 0.3.4 → 0.5.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 +105 -1
- package/dist/index.js +1 -1
- package/dist/lib/app-root.d.ts +11 -0
- package/dist/lib/app-root.d.ts.map +1 -0
- package/dist/lib/app-root.js +38 -0
- package/dist/lib/bootstrap-project.js +2 -2
- package/dist/lib/cli-context.d.ts +6 -0
- package/dist/lib/cli-context.d.ts.map +1 -1
- package/dist/lib/cli-context.js +12 -1
- package/dist/lib/cli.d.ts +3 -2
- package/dist/lib/cli.d.ts.map +1 -1
- package/dist/lib/cli.js +42 -14
- package/dist/lib/commands/completion.js +4 -4
- package/dist/lib/commands/db.d.ts +4 -0
- package/dist/lib/commands/db.d.ts.map +1 -0
- package/dist/lib/commands/db.js +283 -0
- package/dist/lib/commands/doctor.d.ts +5 -0
- package/dist/lib/commands/doctor.d.ts.map +1 -1
- package/dist/lib/commands/doctor.js +26 -251
- package/dist/lib/commands/help.d.ts.map +1 -1
- package/dist/lib/commands/help.js +17 -9
- package/dist/lib/commands/new.js +6 -6
- package/dist/lib/commands/routes.js +6 -6
- package/dist/lib/commands/test.d.ts +20 -1
- package/dist/lib/commands/test.d.ts.map +1 -1
- package/dist/lib/commands/test.js +353 -10
- package/dist/lib/commands/version.js +3 -3
- package/dist/lib/completion.d.ts +1 -1
- package/dist/lib/completion.d.ts.map +1 -1
- package/dist/lib/completion.js +229 -6
- package/dist/lib/controller-files.d.ts +0 -8
- package/dist/lib/controller-files.d.ts.map +1 -1
- package/dist/lib/controller-files.js +0 -23
- package/dist/lib/controller-ownership.d.ts +4 -12
- package/dist/lib/controller-ownership.d.ts.map +1 -1
- package/dist/lib/controller-ownership.js +31 -127
- package/dist/lib/database-command.d.ts +20 -0
- package/dist/lib/database-command.d.ts.map +1 -0
- package/dist/lib/database-command.js +7 -0
- package/dist/lib/doctor/controller-findings.d.ts +2 -2
- package/dist/lib/doctor/controller-findings.d.ts.map +1 -1
- package/dist/lib/doctor/controller-findings.js +23 -39
- package/dist/lib/doctor/controllers.d.ts +1 -2
- package/dist/lib/doctor/controllers.d.ts.map +1 -1
- package/dist/lib/doctor/controllers.js +4 -7
- package/dist/lib/doctor/environment.js +2 -2
- package/dist/lib/doctor/fixes.js +1 -1
- package/dist/lib/doctor/project.d.ts.map +1 -1
- package/dist/lib/doctor/project.js +3 -212
- package/dist/lib/doctor/run.d.ts +9 -0
- package/dist/lib/doctor/run.d.ts.map +1 -0
- package/dist/lib/doctor/run.js +237 -0
- package/dist/lib/doctor/types.d.ts +2 -1
- package/dist/lib/doctor/types.d.ts.map +1 -1
- package/dist/lib/doctor/types.js +4 -1
- package/dist/lib/errors.d.ts +30 -0
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +55 -0
- package/dist/lib/help-text.js +1 -1
- package/dist/lib/parse-args.d.ts.map +1 -1
- package/dist/lib/parse-args.js +17 -4
- package/dist/lib/remix-config.d.ts +75 -0
- package/dist/lib/remix-config.d.ts.map +1 -0
- package/dist/lib/remix-config.js +411 -0
- package/dist/lib/reporter.js +1 -1
- package/dist/lib/route-map.js +13 -33
- package/package.json +13 -7
- package/schema/remix.json +242 -0
- package/src/lib/app-root.ts +46 -0
- package/src/lib/cli-context.ts +17 -0
- package/src/lib/cli.ts +41 -6
- package/src/lib/commands/db.ts +377 -0
- package/src/lib/commands/doctor.ts +27 -329
- package/src/lib/commands/help.ts +10 -1
- package/src/lib/commands/test.ts +453 -12
- package/src/lib/completion.ts +321 -6
- package/src/lib/controller-files.ts +0 -38
- package/src/lib/controller-ownership.ts +50 -203
- package/src/lib/database-command.ts +31 -0
- package/src/lib/doctor/controller-findings.ts +30 -47
- package/src/lib/doctor/controllers.ts +2 -6
- package/src/lib/doctor/project.ts +0 -236
- package/src/lib/doctor/run.ts +311 -0
- package/src/lib/doctor/types.ts +6 -5
- package/src/lib/errors.ts +65 -0
- package/src/lib/parse-args.ts +19 -3
- package/src/lib/remix-config.ts +639 -0
- package/src/lib/route-map.ts +11 -48
- package/template/.agents/skills/remix/SKILL.md +38 -27
- package/template/.agents/skills/remix/references/assets-and-browser-modules.md +54 -11
- package/template/.agents/skills/remix/references/auth-and-sessions.md +5 -5
- package/template/.agents/skills/remix/references/data-and-validation.md +15 -15
- package/template/.agents/skills/remix/references/hydration-frames-navigation.md +63 -9
- package/template/.agents/skills/remix/references/middleware-and-server.md +68 -6
- package/template/.agents/skills/remix/references/mixins-styling-events.md +2 -0
- package/template/.agents/skills/remix/references/routing-and-controllers.md +8 -8
- package/template/.agents/skills/remix/references/testing-patterns.md +19 -18
- package/template/AGENTS.md +6 -3
- package/template/README.md +6 -3
- package/template/app/actions/controller.tsx +1 -1
- package/template/app/{ui → actions}/document.tsx +7 -5
- package/template/app/{ui/scaffold-home-page.tsx → actions/home-page.tsx} +1 -2
- package/template/app/actions/public/entry.ts +48 -0
- package/template/app/{assets → actions/public}/prompt-button.tsx +29 -25
- package/template/app/assets.ts +15 -2
- package/template/app/middleware/render.tsx +8 -2
- package/template/hmr.ts +46 -0
- package/template/package.json +1 -0
- package/template/server.ts +8 -1
- package/template/tsconfig.json +1 -1
- package/dist/lib/doctor/controller-fix-plans.d.ts +0 -4
- package/dist/lib/doctor/controller-fix-plans.d.ts.map +0 -1
- package/dist/lib/doctor/controller-fix-plans.js +0 -119
- package/dist/lib/doctor/controller-placeholders.d.ts +0 -3
- package/dist/lib/doctor/controller-placeholders.d.ts.map +0 -1
- package/dist/lib/doctor/controller-placeholders.js +0 -52
- package/src/lib/doctor/controller-fix-plans.ts +0 -168
- package/src/lib/doctor/controller-placeholders.ts +0 -70
- package/template/app/assets/entry.ts +0 -17
|
@@ -1,50 +1,13 @@
|
|
|
1
|
-
import * as path from 'node:path'
|
|
2
1
|
import * as process from 'node:process'
|
|
3
2
|
|
|
4
|
-
import { checkControllerConventions } from '../doctor/controllers.ts'
|
|
5
3
|
import type { CliContext } from '../cli-context.ts'
|
|
6
|
-
import {
|
|
7
|
-
import { applyDoctorFixPlans } from '../doctor/fixes.ts'
|
|
8
|
-
import { checkProject, getProjectFixPlans } from '../doctor/project.ts'
|
|
9
|
-
import {
|
|
10
|
-
createDoctorSuite,
|
|
11
|
-
createSkippedDoctorSuite,
|
|
12
|
-
type DoctorAppliedFix,
|
|
13
|
-
type DoctorFinding,
|
|
14
|
-
type DoctorReport,
|
|
15
|
-
type DoctorSuiteName,
|
|
16
|
-
type DoctorSuiteResult,
|
|
17
|
-
} from '../doctor/types.ts'
|
|
4
|
+
import { runRemixDoctor, type RunRemixDoctorOptions } from '../doctor/run.ts'
|
|
18
5
|
import { renderCliError, toCliError } from '../errors.ts'
|
|
19
6
|
import { formatHelpText } from '../help-text.ts'
|
|
20
7
|
import { parseArgs } from '../parse-args.ts'
|
|
21
|
-
import {
|
|
22
|
-
createCommandReporter,
|
|
23
|
-
createStepProgressReporter,
|
|
24
|
-
type CommandReporter,
|
|
25
|
-
type StepProgressReporter,
|
|
26
|
-
} from '../reporter.ts'
|
|
8
|
+
import type { RemixDoctorCommandConfig } from '../remix-config.ts'
|
|
27
9
|
|
|
28
|
-
|
|
29
|
-
actions: {
|
|
30
|
-
complete: 'actions',
|
|
31
|
-
running: 'Checking actions',
|
|
32
|
-
},
|
|
33
|
-
environment: {
|
|
34
|
-
complete: 'environment',
|
|
35
|
-
running: 'Checking environment',
|
|
36
|
-
},
|
|
37
|
-
project: {
|
|
38
|
-
complete: 'project',
|
|
39
|
-
running: 'Checking project',
|
|
40
|
-
},
|
|
41
|
-
} satisfies Record<DoctorSuiteName, string | { complete: string; running: string }>
|
|
42
|
-
|
|
43
|
-
interface DoctorCommandOptions {
|
|
44
|
-
fix: boolean
|
|
45
|
-
json: boolean
|
|
46
|
-
strict: boolean
|
|
47
|
-
}
|
|
10
|
+
type DoctorCommandOptions = Pick<RunRemixDoctorOptions, 'fix' | 'json' | 'strict'>
|
|
48
11
|
|
|
49
12
|
export async function runDoctorCommand(argv: string[], context: CliContext): Promise<number> {
|
|
50
13
|
if (argv.includes('-h') || argv.includes('--help')) {
|
|
@@ -52,43 +15,18 @@ export async function runDoctorCommand(argv: string[], context: CliContext): Pro
|
|
|
52
15
|
return 0
|
|
53
16
|
}
|
|
54
17
|
|
|
55
|
-
let reporter: CommandReporter | null = null
|
|
56
|
-
let progress: StepProgressReporter<DoctorSuiteName> | null = null
|
|
57
|
-
|
|
58
18
|
try {
|
|
59
|
-
let
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
})
|
|
67
|
-
progress = reporter == null ? null : createDoctorProgressReporter(reporter)
|
|
68
|
-
if (reporter != null) {
|
|
69
|
-
await reporter.status.commandHeader('doctor')
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
let report = await collectDoctorReport(progress, options, reporter, context)
|
|
73
|
-
|
|
74
|
-
if (options.json) {
|
|
75
|
-
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`)
|
|
76
|
-
} else if (reporter != null) {
|
|
77
|
-
writeDoctorReport(reporter, report)
|
|
78
|
-
reporter.finish()
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if ((options.fix || options.strict) && hasWarningFindings(report.findings)) {
|
|
82
|
-
return 1
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return 0
|
|
19
|
+
let config = await context.loadConfig()
|
|
20
|
+
let options = resolveDoctorCommandOptions(argv, config.doctor)
|
|
21
|
+
return await runRemixDoctor({
|
|
22
|
+
...options,
|
|
23
|
+
cwd: context.cwd,
|
|
24
|
+
remixVersion: context.remixVersion,
|
|
25
|
+
})
|
|
86
26
|
} catch (error) {
|
|
87
|
-
progress?.writeSummaryGap()
|
|
88
27
|
process.stderr.write(
|
|
89
28
|
renderCliError(toCliError(error), { helpText: getDoctorCommandHelpText(process.stderr) }),
|
|
90
29
|
)
|
|
91
|
-
reporter?.finish()
|
|
92
30
|
return 1
|
|
93
31
|
}
|
|
94
32
|
}
|
|
@@ -109,7 +47,11 @@ export function getDoctorCommandHelpText(target: NodeJS.WriteStream = process.st
|
|
|
109
47
|
description: 'Exit with status 1 when warning-level findings are present',
|
|
110
48
|
label: '--strict',
|
|
111
49
|
},
|
|
112
|
-
{
|
|
50
|
+
{
|
|
51
|
+
description: 'Do not exit with status 1 when warning-level findings are present',
|
|
52
|
+
label: '--no-strict',
|
|
53
|
+
},
|
|
54
|
+
{ description: 'Apply available low-risk fixes', label: '--fix' },
|
|
113
55
|
],
|
|
114
56
|
usage: ['remix doctor [--json] [--strict] [--fix] [--no-color]'],
|
|
115
57
|
},
|
|
@@ -117,274 +59,30 @@ export function getDoctorCommandHelpText(target: NodeJS.WriteStream = process.st
|
|
|
117
59
|
)
|
|
118
60
|
}
|
|
119
61
|
|
|
120
|
-
function
|
|
62
|
+
export function resolveDoctorCommandOptions(
|
|
63
|
+
argv: string[],
|
|
64
|
+
config: RemixDoctorCommandConfig | undefined,
|
|
65
|
+
): DoctorCommandOptions {
|
|
121
66
|
let parsed = parseArgs(
|
|
122
67
|
argv,
|
|
123
68
|
{
|
|
124
69
|
fix: { flag: '--fix', type: 'boolean' },
|
|
125
70
|
json: { flag: '--json', type: 'boolean' },
|
|
71
|
+
noStrict: { flag: '--no-strict', type: 'boolean' },
|
|
126
72
|
strict: { flag: '--strict', type: 'boolean' },
|
|
127
73
|
},
|
|
128
74
|
{ maxPositionals: 0 },
|
|
129
75
|
)
|
|
130
76
|
|
|
77
|
+
let strict = config?.strict ?? false
|
|
78
|
+
for (let arg of argv) {
|
|
79
|
+
if (arg === '--strict') strict = true
|
|
80
|
+
if (arg === '--no-strict') strict = false
|
|
81
|
+
}
|
|
82
|
+
|
|
131
83
|
return {
|
|
132
84
|
fix: parsed.options.fix,
|
|
133
85
|
json: parsed.options.json,
|
|
134
|
-
strict
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async function collectDoctorReport(
|
|
139
|
-
progress: StepProgressReporter<DoctorSuiteName> | null,
|
|
140
|
-
options: DoctorCommandOptions,
|
|
141
|
-
reporter: CommandReporter | null,
|
|
142
|
-
context: CliContext,
|
|
143
|
-
): Promise<DoctorReport> {
|
|
144
|
-
let cwd = context.cwd
|
|
145
|
-
let appliedFixes: DoctorAppliedFix[] = []
|
|
146
|
-
let environment = await runDoctorSuite(progress, 'environment', async () => {
|
|
147
|
-
let result = await checkEnvironment(cwd)
|
|
148
|
-
let suiteAppliedFixes: DoctorAppliedFix[] = []
|
|
149
|
-
let finalResult = result
|
|
150
|
-
|
|
151
|
-
if (options.fix && result.projectRoot != null) {
|
|
152
|
-
let fixPlans = getEnvironmentFixPlans(result, context.remixVersion)
|
|
153
|
-
if (fixPlans.length > 0) {
|
|
154
|
-
suiteAppliedFixes = await applyDoctorFixPlans(result.projectRoot, fixPlans)
|
|
155
|
-
finalResult = await checkEnvironment(result.projectRoot)
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
let suite = finalResult.suite
|
|
160
|
-
if (suiteAppliedFixes.length > 0) {
|
|
161
|
-
suite = {
|
|
162
|
-
...suite,
|
|
163
|
-
appliedFixes: suiteAppliedFixes,
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return {
|
|
168
|
-
appliedFixes: suiteAppliedFixes,
|
|
169
|
-
projectRoot: finalResult.projectRoot ?? result.projectRoot,
|
|
170
|
-
suite,
|
|
171
|
-
}
|
|
172
|
-
})
|
|
173
|
-
let findings = [...environment.suite.findings]
|
|
174
|
-
appliedFixes.push(...(environment.appliedFixes ?? []))
|
|
175
|
-
let suites: DoctorSuiteResult[] = [environment.suite]
|
|
176
|
-
let routesFile =
|
|
177
|
-
environment.projectRoot == null
|
|
178
|
-
? undefined
|
|
179
|
-
: path.join(environment.projectRoot, 'app', 'routes.ts')
|
|
180
|
-
writeDoctorSuiteDetails(reporter, environment.suite)
|
|
181
|
-
progress?.writeSummaryGap()
|
|
182
|
-
|
|
183
|
-
if (hasWarningFindings(environment.suite.findings)) {
|
|
184
|
-
let projectSuite = createSkippedDoctorSuite('project', 'Blocked by environment warnings.')
|
|
185
|
-
let actionsSuite = createSkippedDoctorSuite('actions', 'Blocked by environment warnings.')
|
|
186
|
-
suites.push(projectSuite, actionsSuite)
|
|
187
|
-
progress?.skip(projectSuite.name, projectSuite.reason)
|
|
188
|
-
writeDoctorSuiteDetails(reporter, projectSuite)
|
|
189
|
-
progress?.writeSummaryGap()
|
|
190
|
-
progress?.skip(actionsSuite.name, actionsSuite.reason)
|
|
191
|
-
writeDoctorSuiteDetails(reporter, actionsSuite)
|
|
192
|
-
progress?.writeSummaryGap()
|
|
193
|
-
|
|
194
|
-
return {
|
|
195
|
-
appRoot: environment.projectRoot,
|
|
196
|
-
appliedFixes,
|
|
197
|
-
findings,
|
|
198
|
-
remainingFindings: findings,
|
|
199
|
-
routesFile,
|
|
200
|
-
suites,
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
let project = await runDoctorSuite(progress, 'project', async () => {
|
|
205
|
-
let result = await checkProject(environment.projectRoot!)
|
|
206
|
-
let suiteAppliedFixes: DoctorAppliedFix[] = []
|
|
207
|
-
let finalResult = result
|
|
208
|
-
|
|
209
|
-
if (options.fix) {
|
|
210
|
-
let fixPlans = await getProjectFixPlans(environment.projectRoot!)
|
|
211
|
-
if (fixPlans.length > 0) {
|
|
212
|
-
suiteAppliedFixes = await applyDoctorFixPlans(environment.projectRoot!, fixPlans)
|
|
213
|
-
finalResult = await checkProject(environment.projectRoot!)
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
let suite = finalResult.suite
|
|
218
|
-
if (suiteAppliedFixes.length > 0) {
|
|
219
|
-
suite = {
|
|
220
|
-
...suite,
|
|
221
|
-
appliedFixes: suiteAppliedFixes,
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return {
|
|
226
|
-
appliedFixes: suiteAppliedFixes,
|
|
227
|
-
routeManifest: finalResult.routeManifest,
|
|
228
|
-
routesFile: finalResult.routesFile,
|
|
229
|
-
suite,
|
|
230
|
-
}
|
|
231
|
-
})
|
|
232
|
-
findings.push(...project.suite.findings)
|
|
233
|
-
appliedFixes.push(...(project.appliedFixes ?? []))
|
|
234
|
-
routesFile = project.routesFile
|
|
235
|
-
suites.push(project.suite)
|
|
236
|
-
writeDoctorSuiteDetails(reporter, project.suite)
|
|
237
|
-
progress?.writeSummaryGap()
|
|
238
|
-
|
|
239
|
-
if (hasWarningFindings(project.suite.findings)) {
|
|
240
|
-
let actionsSuite = createSkippedDoctorSuite('actions', 'Blocked by project warnings.')
|
|
241
|
-
suites.push(actionsSuite)
|
|
242
|
-
progress?.skip(actionsSuite.name, actionsSuite.reason)
|
|
243
|
-
writeDoctorSuiteDetails(reporter, actionsSuite)
|
|
244
|
-
progress?.writeSummaryGap()
|
|
245
|
-
|
|
246
|
-
return {
|
|
247
|
-
appRoot: environment.projectRoot,
|
|
248
|
-
appliedFixes,
|
|
249
|
-
findings,
|
|
250
|
-
remainingFindings: findings,
|
|
251
|
-
routesFile,
|
|
252
|
-
suites,
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
let actions = await runDoctorSuite(progress, 'actions', async () => {
|
|
257
|
-
let controllerResult = await checkControllerConventions(
|
|
258
|
-
project.routeManifest!.appRoot,
|
|
259
|
-
project.routeManifest!.tree,
|
|
260
|
-
)
|
|
261
|
-
let remainingFindings = controllerResult.suite.findings
|
|
262
|
-
let suiteAppliedFixes: DoctorAppliedFix[] = []
|
|
263
|
-
|
|
264
|
-
if (options.fix && controllerResult.fixPlans.length > 0) {
|
|
265
|
-
suiteAppliedFixes = await applyDoctorFixPlans(
|
|
266
|
-
project.routeManifest!.appRoot,
|
|
267
|
-
controllerResult.fixPlans,
|
|
268
|
-
)
|
|
269
|
-
let finalControllerResult = await checkControllerConventions(
|
|
270
|
-
project.routeManifest!.appRoot,
|
|
271
|
-
project.routeManifest!.tree,
|
|
272
|
-
)
|
|
273
|
-
remainingFindings = finalControllerResult.suite.findings
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
let suite = createDoctorSuite('actions', remainingFindings)
|
|
277
|
-
if (suiteAppliedFixes.length > 0) {
|
|
278
|
-
suite.appliedFixes = suiteAppliedFixes
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
return { appliedFixes: suiteAppliedFixes, suite }
|
|
282
|
-
})
|
|
283
|
-
|
|
284
|
-
findings.push(...actions.suite.findings)
|
|
285
|
-
appliedFixes.push(...(actions.appliedFixes ?? []))
|
|
286
|
-
suites.push(actions.suite)
|
|
287
|
-
writeDoctorSuiteDetails(reporter, actions.suite)
|
|
288
|
-
progress?.writeSummaryGap()
|
|
289
|
-
|
|
290
|
-
let report: DoctorReport = {
|
|
291
|
-
appRoot: environment.projectRoot,
|
|
292
|
-
findings,
|
|
293
|
-
routesFile,
|
|
294
|
-
suites,
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
if (options.fix) {
|
|
298
|
-
report.appliedFixes = appliedFixes
|
|
299
|
-
report.remainingFindings = findings
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
return report
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
function hasWarningFindings(findings: DoctorFinding[]): boolean {
|
|
306
|
-
return findings.some((finding) => finding.severity === 'warn')
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
function formatAppliedFix(appliedFix: DoctorAppliedFix): string {
|
|
310
|
-
if (appliedFix.kind === 'update-file') {
|
|
311
|
-
return `Updated ${appliedFix.path}`
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
return `Created ${appliedFix.path}`
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
async function runDoctorSuite<
|
|
318
|
-
result extends { appliedFixes?: DoctorAppliedFix[]; suite: DoctorSuiteResult },
|
|
319
|
-
>(
|
|
320
|
-
progress: StepProgressReporter<DoctorSuiteName> | null,
|
|
321
|
-
label: DoctorSuiteName,
|
|
322
|
-
callback: () => Promise<result>,
|
|
323
|
-
): Promise<result> {
|
|
324
|
-
progress?.start(label)
|
|
325
|
-
|
|
326
|
-
try {
|
|
327
|
-
let result = await callback()
|
|
328
|
-
|
|
329
|
-
if (result.suite.status === 'ok') {
|
|
330
|
-
progress?.succeed(label)
|
|
331
|
-
} else if (result.suite.status === 'issues') {
|
|
332
|
-
progress?.fail(label)
|
|
333
|
-
} else {
|
|
334
|
-
progress?.skip(label, result.suite.reason)
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
return result
|
|
338
|
-
} catch (error) {
|
|
339
|
-
progress?.fail(label)
|
|
340
|
-
throw error
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
function createDoctorProgressReporter(
|
|
345
|
-
reporter: CommandReporter,
|
|
346
|
-
): StepProgressReporter<DoctorSuiteName> {
|
|
347
|
-
return createStepProgressReporter(reporter.status, DOCTOR_SUITE_LABELS)
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
function writeDoctorReport(reporter: CommandReporter, report: DoctorReport): void {
|
|
351
|
-
let warningCount = report.findings.filter((finding) => finding.severity === 'warn').length
|
|
352
|
-
let adviceCount = report.findings.length - warningCount
|
|
353
|
-
|
|
354
|
-
if ((report.appliedFixes?.length ?? 0) > 0) {
|
|
355
|
-
let fixCount = report.appliedFixes!.length
|
|
356
|
-
reporter.out.line(`Applied ${fixCount} ${fixCount === 1 ? 'fix' : 'fixes'}.`)
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
if (report.findings.length === 0) {
|
|
360
|
-
reporter.out.line('Doctor found no issues.')
|
|
86
|
+
strict,
|
|
361
87
|
}
|
|
362
|
-
|
|
363
|
-
reporter.out.line(`Summary: ${warningCount} warnings, ${adviceCount} advice.`)
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
function writeDoctorSuiteDetails(reporter: CommandReporter | null, suite: DoctorSuiteResult): void {
|
|
367
|
-
if (reporter == null) {
|
|
368
|
-
return
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
if (suite.findings.length === 0 && (suite.appliedFixes?.length ?? 0) === 0) {
|
|
372
|
-
return
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
reporter.out.withIndent(() => {
|
|
376
|
-
for (let finding of suite.findings) {
|
|
377
|
-
reporter.out.bullet(
|
|
378
|
-
reporter.out.label(finding.severity.toUpperCase(), finding.message, {
|
|
379
|
-
tone: finding.severity === 'warn' ? 'warn' : undefined,
|
|
380
|
-
}),
|
|
381
|
-
)
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
if ((suite.appliedFixes?.length ?? 0) > 0) {
|
|
385
|
-
reporter.out.section('Applied fixes:', () => {
|
|
386
|
-
reporter.out.bullets((suite.appliedFixes ?? []).map(formatAppliedFix))
|
|
387
|
-
})
|
|
388
|
-
}
|
|
389
|
-
})
|
|
390
88
|
}
|
package/src/lib/commands/help.ts
CHANGED
|
@@ -27,6 +27,7 @@ export function getCliHelpText(target: NodeJS.WriteStream = process.stdout): str
|
|
|
27
27
|
{ description: 'Print shell completion scripts for Remix', label: 'completion' },
|
|
28
28
|
{ description: 'Show help for Remix commands', label: 'help [command]' },
|
|
29
29
|
{ description: 'Create a new Remix project', label: 'new <name>' },
|
|
30
|
+
{ description: 'Manage the current app database', label: 'db <command>' },
|
|
30
31
|
{ description: 'Check project health for the current project', label: 'doctor' },
|
|
31
32
|
{ description: 'Show the route tree for the current project', label: 'routes' },
|
|
32
33
|
{ description: 'Run tests for the current project', label: 'test [glob]' },
|
|
@@ -37,6 +38,7 @@ export function getCliHelpText(target: NodeJS.WriteStream = process.stdout): str
|
|
|
37
38
|
'remix help',
|
|
38
39
|
'remix help completion',
|
|
39
40
|
'remix help doctor',
|
|
41
|
+
'remix db status',
|
|
40
42
|
'remix doctor',
|
|
41
43
|
'remix new my-remix-app',
|
|
42
44
|
'remix new my-remix-app --app-name "My Remix App"',
|
|
@@ -45,6 +47,7 @@ export function getCliHelpText(target: NodeJS.WriteStream = process.stdout): str
|
|
|
45
47
|
'remix version',
|
|
46
48
|
],
|
|
47
49
|
options: [
|
|
50
|
+
{ description: 'Use a custom Remix config file', label: '--config <path>' },
|
|
48
51
|
{ description: 'Show help', label: '-h, --help' },
|
|
49
52
|
{ description: 'Disable ANSI color output', label: '--no-color' },
|
|
50
53
|
{ description: 'Show version', label: '-v, --version' },
|
|
@@ -62,6 +65,7 @@ export function getHelpCommandHelpText(target: NodeJS.WriteStream = process.stdo
|
|
|
62
65
|
examples: [
|
|
63
66
|
'remix help',
|
|
64
67
|
'remix help completion',
|
|
68
|
+
'remix help db',
|
|
65
69
|
'remix help doctor',
|
|
66
70
|
'remix help new',
|
|
67
71
|
'remix help routes',
|
|
@@ -100,6 +104,11 @@ async function getCommandHelpText(argv: string[]): Promise<string> {
|
|
|
100
104
|
return getDoctorCommandHelpText()
|
|
101
105
|
}
|
|
102
106
|
|
|
107
|
+
if (command === 'db' && rest.length === 0) {
|
|
108
|
+
let { getDbCommandHelpText } = await import('./db.ts')
|
|
109
|
+
return getDbCommandHelpText()
|
|
110
|
+
}
|
|
111
|
+
|
|
103
112
|
if (command === 'routes' && rest.length === 0) {
|
|
104
113
|
let { getRoutesCommandHelpText } = await import('./routes.ts')
|
|
105
114
|
return getRoutesCommandHelpText()
|
|
@@ -107,7 +116,7 @@ async function getCommandHelpText(argv: string[]): Promise<string> {
|
|
|
107
116
|
|
|
108
117
|
if (command === 'test' && rest.length === 0) {
|
|
109
118
|
let { getTestCommandHelpText } = await import('./test.ts')
|
|
110
|
-
return
|
|
119
|
+
return getTestCommandHelpText()
|
|
111
120
|
}
|
|
112
121
|
|
|
113
122
|
if (command === 'version' && rest.length === 0) {
|