@remix-run/cli 0.0.0 → 0.1.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 (155) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -3
  3. package/bootstrap/AGENTS.md +35 -0
  4. package/bootstrap/README.md +27 -0
  5. package/bootstrap/app/controllers/auth.tsx +21 -0
  6. package/bootstrap/app/controllers/home.tsx +26 -0
  7. package/bootstrap/app/router.ts +10 -0
  8. package/bootstrap/app/routes.ts +6 -0
  9. package/bootstrap/app/ui/document.tsx +21 -0
  10. package/bootstrap/app/ui/layout.tsx +22 -0
  11. package/bootstrap/app/utils/render.tsx +7 -0
  12. package/bootstrap/package.json +22 -0
  13. package/bootstrap/server.ts +37 -0
  14. package/bootstrap/tsconfig.json +19 -0
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +1 -0
  18. package/dist/lib/bootstrap-project.d.ts +17 -0
  19. package/dist/lib/bootstrap-project.d.ts.map +1 -0
  20. package/dist/lib/bootstrap-project.js +137 -0
  21. package/dist/lib/cli-context.d.ts +11 -0
  22. package/dist/lib/cli-context.d.ts.map +1 -0
  23. package/dist/lib/cli-context.js +19 -0
  24. package/dist/lib/cli.d.ts +6 -0
  25. package/dist/lib/cli.d.ts.map +1 -0
  26. package/dist/lib/cli.js +87 -0
  27. package/dist/lib/commands/completion.d.ts +3 -0
  28. package/dist/lib/commands/completion.d.ts.map +1 -0
  29. package/dist/lib/commands/completion.js +51 -0
  30. package/dist/lib/commands/doctor.d.ts +4 -0
  31. package/dist/lib/commands/doctor.d.ts.map +1 -0
  32. package/dist/lib/commands/doctor.js +293 -0
  33. package/dist/lib/commands/help.d.ts +4 -0
  34. package/dist/lib/commands/help.d.ts.map +1 -0
  35. package/dist/lib/commands/help.js +124 -0
  36. package/dist/lib/commands/new.d.ts +4 -0
  37. package/dist/lib/commands/new.d.ts.map +1 -0
  38. package/dist/lib/commands/new.js +70 -0
  39. package/dist/lib/commands/routes.d.ts +4 -0
  40. package/dist/lib/commands/routes.d.ts.map +1 -0
  41. package/dist/lib/commands/routes.js +161 -0
  42. package/dist/lib/commands/skills.d.ts +6 -0
  43. package/dist/lib/commands/skills.d.ts.map +1 -0
  44. package/dist/lib/commands/skills.js +222 -0
  45. package/dist/lib/commands/test.d.ts +4 -0
  46. package/dist/lib/commands/test.d.ts.map +1 -0
  47. package/dist/lib/commands/test.js +19 -0
  48. package/dist/lib/commands/version.d.ts +4 -0
  49. package/dist/lib/commands/version.d.ts.map +1 -0
  50. package/dist/lib/commands/version.js +29 -0
  51. package/dist/lib/completion.d.ts +12 -0
  52. package/dist/lib/completion.d.ts.map +1 -0
  53. package/dist/lib/completion.js +408 -0
  54. package/dist/lib/contained-path.d.ts +2 -0
  55. package/dist/lib/contained-path.d.ts.map +1 -0
  56. package/dist/lib/contained-path.js +10 -0
  57. package/dist/lib/controller-files.d.ts +14 -0
  58. package/dist/lib/controller-files.d.ts.map +1 -0
  59. package/dist/lib/controller-files.js +53 -0
  60. package/dist/lib/controller-ownership.d.ts +41 -0
  61. package/dist/lib/controller-ownership.d.ts.map +1 -0
  62. package/dist/lib/controller-ownership.js +224 -0
  63. package/dist/lib/display-path.d.ts +2 -0
  64. package/dist/lib/display-path.d.ts.map +1 -0
  65. package/dist/lib/display-path.js +12 -0
  66. package/dist/lib/doctor/controller-findings.d.ts +4 -0
  67. package/dist/lib/doctor/controller-findings.d.ts.map +1 -0
  68. package/dist/lib/doctor/controller-findings.js +132 -0
  69. package/dist/lib/doctor/controller-fix-plans.d.ts +4 -0
  70. package/dist/lib/doctor/controller-fix-plans.d.ts.map +1 -0
  71. package/dist/lib/doctor/controller-fix-plans.js +130 -0
  72. package/dist/lib/doctor/controller-placeholders.d.ts +4 -0
  73. package/dist/lib/doctor/controller-placeholders.d.ts.map +1 -0
  74. package/dist/lib/doctor/controller-placeholders.js +183 -0
  75. package/dist/lib/doctor/controllers.d.ts +8 -0
  76. package/dist/lib/doctor/controllers.d.ts.map +1 -0
  77. package/dist/lib/doctor/controllers.js +13 -0
  78. package/dist/lib/doctor/environment.d.ts +17 -0
  79. package/dist/lib/doctor/environment.d.ts.map +1 -0
  80. package/dist/lib/doctor/environment.js +226 -0
  81. package/dist/lib/doctor/fixes.d.ts +3 -0
  82. package/dist/lib/doctor/fixes.d.ts.map +1 -0
  83. package/dist/lib/doctor/fixes.js +65 -0
  84. package/dist/lib/doctor/project.d.ts +10 -0
  85. package/dist/lib/doctor/project.d.ts.map +1 -0
  86. package/dist/lib/doctor/project.js +371 -0
  87. package/dist/lib/doctor/types.d.ts +48 -0
  88. package/dist/lib/doctor/types.d.ts.map +1 -0
  89. package/dist/lib/doctor/types.js +15 -0
  90. package/dist/lib/errors.d.ts +173 -0
  91. package/dist/lib/errors.d.ts.map +1 -0
  92. package/dist/lib/errors.js +318 -0
  93. package/dist/lib/help-text.d.ts +13 -0
  94. package/dist/lib/help-text.d.ts.map +1 -0
  95. package/dist/lib/help-text.js +43 -0
  96. package/dist/lib/load-route-map-worker.d.ts +2 -0
  97. package/dist/lib/load-route-map-worker.d.ts.map +1 -0
  98. package/dist/lib/load-route-map-worker.js +92 -0
  99. package/dist/lib/parse-args.d.ts +22 -0
  100. package/dist/lib/parse-args.d.ts.map +1 -0
  101. package/dist/lib/parse-args.js +35 -0
  102. package/dist/lib/remix-version.d.ts +2 -0
  103. package/dist/lib/remix-version.d.ts.map +1 -0
  104. package/dist/lib/remix-version.js +58 -0
  105. package/dist/lib/reporter.d.ts +56 -0
  106. package/dist/lib/reporter.d.ts.map +1 -0
  107. package/dist/lib/reporter.js +357 -0
  108. package/dist/lib/route-map.d.ts +38 -0
  109. package/dist/lib/route-map.d.ts.map +1 -0
  110. package/dist/lib/route-map.js +195 -0
  111. package/dist/lib/skills-cache.d.ts +19 -0
  112. package/dist/lib/skills-cache.d.ts.map +1 -0
  113. package/dist/lib/skills-cache.js +89 -0
  114. package/dist/lib/skills.d.ts +30 -0
  115. package/dist/lib/skills.d.ts.map +1 -0
  116. package/dist/lib/skills.js +441 -0
  117. package/dist/lib/terminal.d.ts +17 -0
  118. package/dist/lib/terminal.d.ts.map +1 -0
  119. package/dist/lib/terminal.js +66 -0
  120. package/package.json +48 -5
  121. package/src/index.ts +1 -0
  122. package/src/lib/bootstrap-project.ts +222 -0
  123. package/src/lib/cli-context.ts +38 -0
  124. package/src/lib/cli.ts +120 -0
  125. package/src/lib/commands/completion.ts +74 -0
  126. package/src/lib/commands/doctor.ts +393 -0
  127. package/src/lib/commands/help.ts +157 -0
  128. package/src/lib/commands/new.ts +104 -0
  129. package/src/lib/commands/routes.ts +251 -0
  130. package/src/lib/commands/skills.ts +306 -0
  131. package/src/lib/commands/test.ts +25 -0
  132. package/src/lib/commands/version.ts +39 -0
  133. package/src/lib/completion.ts +561 -0
  134. package/src/lib/contained-path.ts +13 -0
  135. package/src/lib/controller-files.ts +79 -0
  136. package/src/lib/controller-ownership.ts +397 -0
  137. package/src/lib/display-path.ts +16 -0
  138. package/src/lib/doctor/controller-findings.ts +157 -0
  139. package/src/lib/doctor/controller-fix-plans.ts +184 -0
  140. package/src/lib/doctor/controller-placeholders.ts +242 -0
  141. package/src/lib/doctor/controllers.ts +23 -0
  142. package/src/lib/doctor/environment.ts +289 -0
  143. package/src/lib/doctor/fixes.ts +84 -0
  144. package/src/lib/doctor/project.ts +435 -0
  145. package/src/lib/doctor/types.ts +95 -0
  146. package/src/lib/errors.ts +379 -0
  147. package/src/lib/help-text.ts +88 -0
  148. package/src/lib/load-route-map-worker.ts +110 -0
  149. package/src/lib/parse-args.ts +82 -0
  150. package/src/lib/remix-version.ts +80 -0
  151. package/src/lib/reporter.ts +535 -0
  152. package/src/lib/route-map.ts +303 -0
  153. package/src/lib/skills-cache.ts +140 -0
  154. package/src/lib/skills.ts +706 -0
  155. package/src/lib/terminal.ts +86 -0
@@ -0,0 +1,408 @@
1
+ const COMPLETION_SHELLS = ['bash', 'zsh'];
2
+ const HELP_COMMANDS = [
3
+ 'completion',
4
+ 'doctor',
5
+ 'help',
6
+ 'new',
7
+ 'routes',
8
+ 'skills',
9
+ 'test',
10
+ 'version',
11
+ ];
12
+ const ROOT_COMMANDS = [
13
+ 'completion',
14
+ 'doctor',
15
+ 'help',
16
+ 'new',
17
+ 'routes',
18
+ 'skills',
19
+ 'test',
20
+ 'version',
21
+ ];
22
+ const SKILLS_COMMANDS = ['install', 'list'];
23
+ export function isCompletionShell(value) {
24
+ return COMPLETION_SHELLS.includes(value);
25
+ }
26
+ export function getCompletionResult(words, currentIndex) {
27
+ let resolvedIndex = Math.max(0, currentIndex);
28
+ let currentWord = words[resolvedIndex] ?? '';
29
+ let tokens = getTokensBeforeCursor(words, resolvedIndex);
30
+ return completeTopLevel(tokens, currentWord);
31
+ }
32
+ export function renderCompletionResult(result) {
33
+ let lines = [`mode:${result.mode}`];
34
+ if (result.mode === 'values') {
35
+ lines.push(...(result.values ?? []));
36
+ }
37
+ return `${lines.join('\n')}\n`;
38
+ }
39
+ export function getCompletionScript() {
40
+ return `###-begin-remix-completion-###
41
+ #
42
+ # Remix command completion script
43
+ #
44
+ # Installation:
45
+ # remix completion bash >> ~/.bashrc
46
+ # remix completion zsh >> ~/.zshrc
47
+ #
48
+
49
+ if type complete &>/dev/null; then
50
+ _remix_completion() {
51
+ local words cword current output mode si
52
+ local lines
53
+
54
+ if type _get_comp_words_by_ref &>/dev/null; then
55
+ _get_comp_words_by_ref -w words -i cword
56
+ else
57
+ cword="$COMP_CWORD"
58
+ words=("\${COMP_WORDS[@]}")
59
+ fi
60
+
61
+ current="\${words[cword]}"
62
+ output=$(remix completion -- "$cword" "\${words[@]}" 2>/dev/null) || return 0
63
+ si="$IFS"
64
+ IFS=$'\\n' lines=($output)
65
+ IFS="$si"
66
+ mode="\${lines[0]}"
67
+
68
+ if [[ "$mode" == "mode:values" ]]; then
69
+ COMPREPLY=("\${lines[@]:1}")
70
+ return 0
71
+ fi
72
+
73
+ if [[ "$mode" == "mode:files" ]]; then
74
+ COMPREPLY=($(compgen -f -- "$current"))
75
+ return 0
76
+ fi
77
+
78
+ COMPREPLY=()
79
+ }
80
+
81
+ complete -o default -F _remix_completion remix
82
+ elif type compdef &>/dev/null; then
83
+ _remix_completion() {
84
+ local output mode
85
+ local -a lines values
86
+
87
+ output=$(remix completion -- "$((CURRENT - 1))" "\${words[@]}" 2>/dev/null) || return 0
88
+ lines=("\${(@f)output}")
89
+ mode="\${lines[1]}"
90
+
91
+ if [[ "$mode" == "mode:values" ]]; then
92
+ values=("\${(@)lines[2,-1]}")
93
+ if (( \${#values[@]} > 0 )); then
94
+ compadd -- "\${values[@]}"
95
+ fi
96
+ return 0
97
+ fi
98
+
99
+ if [[ "$mode" == "mode:files" ]]; then
100
+ if autoload -U +X _files 2>/dev/null; then
101
+ _files
102
+ else
103
+ compadd -f
104
+ fi
105
+ return 0
106
+ fi
107
+
108
+ return 0
109
+ }
110
+
111
+ compdef _remix_completion remix
112
+ fi
113
+ ###-end-remix-completion-###
114
+ `;
115
+ }
116
+ function completeTopLevel(tokens, currentWord) {
117
+ let usedFlags = new Set();
118
+ let index = 0;
119
+ while (index < tokens.length) {
120
+ let token = tokens[index];
121
+ if (token === '--no-color') {
122
+ usedFlags.add('--no-color');
123
+ index++;
124
+ continue;
125
+ }
126
+ if (token === '-h' || token === '--help') {
127
+ usedFlags.add('-h');
128
+ return completeValues([], currentWord);
129
+ }
130
+ if (token === '-v' || token === '--version') {
131
+ usedFlags.add('-v');
132
+ return completeValues([], currentWord);
133
+ }
134
+ return completeCommand(token, tokens.slice(index + 1), currentWord, usedFlags);
135
+ }
136
+ return completeValues(getTopLevelSuggestions(currentWord, usedFlags), currentWord);
137
+ }
138
+ function completeCommand(command, tokens, currentWord, usedGlobalFlags) {
139
+ if (command === 'help') {
140
+ return completeHelp(tokens, currentWord, usedGlobalFlags);
141
+ }
142
+ if (command === 'new') {
143
+ return completeNew(tokens, currentWord, usedGlobalFlags);
144
+ }
145
+ if (command === 'doctor') {
146
+ return completeSimpleFlags(tokens, currentWord, usedGlobalFlags, [
147
+ '--fix',
148
+ '--json',
149
+ '--strict',
150
+ ]);
151
+ }
152
+ if (command === 'routes') {
153
+ return completeRoutes(tokens, currentWord, usedGlobalFlags);
154
+ }
155
+ if (command === 'skills') {
156
+ return completeSkills(tokens, currentWord, usedGlobalFlags);
157
+ }
158
+ if (command === 'version') {
159
+ return completeSimpleFlags(tokens, currentWord, usedGlobalFlags, []);
160
+ }
161
+ if (command === 'test') {
162
+ return completeSimpleFlags(tokens, currentWord, usedGlobalFlags, [
163
+ '--coverage',
164
+ '--watch',
165
+ '--help',
166
+ ]);
167
+ }
168
+ if (command === 'completion') {
169
+ return completeCompletionCommand(tokens, currentWord, usedGlobalFlags);
170
+ }
171
+ return completeValues([], currentWord);
172
+ }
173
+ function completeHelp(tokens, currentWord, usedGlobalFlags) {
174
+ let filteredTokens = filterGlobalCommandTokens(tokens, usedGlobalFlags);
175
+ if (filteredTokens == null) {
176
+ return completeValues([], currentWord);
177
+ }
178
+ if (filteredTokens.length === 0) {
179
+ return completeValues(withHelpFlags([...HELP_COMMANDS], usedGlobalFlags), currentWord);
180
+ }
181
+ let [topic, ...rest] = filteredTokens;
182
+ if (rest.length === 0) {
183
+ if (topic === 'skills') {
184
+ return completeValues(withHelpFlags([...SKILLS_COMMANDS], usedGlobalFlags), currentWord);
185
+ }
186
+ return completeValues([], currentWord);
187
+ }
188
+ return completeValues([], currentWord);
189
+ }
190
+ function completeNew(tokens, currentWord, usedGlobalFlags) {
191
+ let filteredTokens = filterGlobalCommandTokens(tokens, usedGlobalFlags);
192
+ if (filteredTokens == null) {
193
+ return completeValues([], currentWord);
194
+ }
195
+ let hasAppName = false;
196
+ let hasForce = false;
197
+ let hasTargetDir = false;
198
+ let expectsAppName = false;
199
+ for (let token of filteredTokens) {
200
+ if (expectsAppName) {
201
+ expectsAppName = false;
202
+ continue;
203
+ }
204
+ if (token === '--app-name') {
205
+ hasAppName = true;
206
+ expectsAppName = true;
207
+ continue;
208
+ }
209
+ if (token === '--force') {
210
+ hasForce = true;
211
+ continue;
212
+ }
213
+ if (token.startsWith('-')) {
214
+ return completeValues([], currentWord);
215
+ }
216
+ if (!hasTargetDir) {
217
+ hasTargetDir = true;
218
+ continue;
219
+ }
220
+ return completeValues([], currentWord);
221
+ }
222
+ if (expectsAppName) {
223
+ return { mode: 'none' };
224
+ }
225
+ let flags = withHelpFlags([...(!hasAppName ? ['--app-name'] : []), ...(!hasForce ? ['--force'] : [])], usedGlobalFlags);
226
+ if (!hasTargetDir && !currentWord.startsWith('-')) {
227
+ return { mode: 'files' };
228
+ }
229
+ return completeValues(flags, currentWord);
230
+ }
231
+ function completeRoutes(tokens, currentWord, usedGlobalFlags) {
232
+ let filteredTokens = filterGlobalCommandTokens(tokens, usedGlobalFlags);
233
+ if (filteredTokens == null) {
234
+ return completeValues([], currentWord);
235
+ }
236
+ let hasJson = false;
237
+ let hasNoHeaders = false;
238
+ let hasTable = false;
239
+ let hasVerbose = false;
240
+ for (let token of filteredTokens) {
241
+ if (token === '--json') {
242
+ hasJson = true;
243
+ continue;
244
+ }
245
+ if (token === '--table') {
246
+ hasTable = true;
247
+ continue;
248
+ }
249
+ if (token === '--no-headers') {
250
+ hasNoHeaders = true;
251
+ continue;
252
+ }
253
+ if (token === '--verbose') {
254
+ hasVerbose = true;
255
+ continue;
256
+ }
257
+ return completeValues([], currentWord);
258
+ }
259
+ let flags = withHelpFlags([
260
+ ...(!hasJson && !hasTable && !hasVerbose ? ['--json'] : []),
261
+ ...(!hasTable && !hasJson ? ['--table'] : []),
262
+ ...(!hasNoHeaders && hasTable ? ['--no-headers'] : []),
263
+ ...(!hasVerbose && !hasJson ? ['--verbose'] : []),
264
+ ], usedGlobalFlags);
265
+ return completeValues(flags, currentWord);
266
+ }
267
+ function completeSkills(tokens, currentWord, usedGlobalFlags) {
268
+ let filteredTokens = filterGlobalCommandTokens(tokens, usedGlobalFlags);
269
+ if (filteredTokens == null) {
270
+ return completeValues([], currentWord);
271
+ }
272
+ if (filteredTokens.length === 0) {
273
+ return completeValues(withHelpFlags([...SKILLS_COMMANDS], usedGlobalFlags), currentWord);
274
+ }
275
+ let [subcommand, ...rest] = filteredTokens;
276
+ if (subcommand === 'install') {
277
+ return completeSkillsInstall(rest, currentWord, usedGlobalFlags);
278
+ }
279
+ if (subcommand === 'list') {
280
+ return completeSkillsList(rest, currentWord, usedGlobalFlags);
281
+ }
282
+ return completeValues([], currentWord);
283
+ }
284
+ function completeSkillsInstall(tokens, currentWord, usedGlobalFlags) {
285
+ let filteredTokens = filterGlobalCommandTokens(tokens, usedGlobalFlags);
286
+ if (filteredTokens == null) {
287
+ return completeValues([], currentWord);
288
+ }
289
+ let hasDir = false;
290
+ let expectsDir = false;
291
+ for (let token of filteredTokens) {
292
+ if (expectsDir) {
293
+ expectsDir = false;
294
+ continue;
295
+ }
296
+ if (token === '--dir') {
297
+ hasDir = true;
298
+ expectsDir = true;
299
+ continue;
300
+ }
301
+ return completeValues([], currentWord);
302
+ }
303
+ if (expectsDir) {
304
+ return { mode: 'files' };
305
+ }
306
+ return completeValues(withHelpFlags(!hasDir ? ['--dir'] : [], usedGlobalFlags), currentWord);
307
+ }
308
+ function completeSkillsList(tokens, currentWord, usedGlobalFlags) {
309
+ return completeSkillsDirectoryCommand(tokens, currentWord, usedGlobalFlags);
310
+ }
311
+ function completeSkillsDirectoryCommand(tokens, currentWord, usedGlobalFlags) {
312
+ let filteredTokens = filterGlobalCommandTokens(tokens, usedGlobalFlags);
313
+ if (filteredTokens == null) {
314
+ return completeValues([], currentWord);
315
+ }
316
+ let hasDir = false;
317
+ let hasJson = false;
318
+ let expectsDir = false;
319
+ for (let token of filteredTokens) {
320
+ if (expectsDir) {
321
+ expectsDir = false;
322
+ continue;
323
+ }
324
+ if (token === '--dir') {
325
+ hasDir = true;
326
+ expectsDir = true;
327
+ continue;
328
+ }
329
+ if (token === '--json') {
330
+ hasJson = true;
331
+ continue;
332
+ }
333
+ return completeValues([], currentWord);
334
+ }
335
+ if (expectsDir) {
336
+ return { mode: 'files' };
337
+ }
338
+ return completeValues(withHelpFlags([...(!hasDir ? ['--dir'] : []), ...(!hasJson ? ['--json'] : [])], usedGlobalFlags), currentWord);
339
+ }
340
+ function completeCompletionCommand(tokens, currentWord, usedGlobalFlags) {
341
+ let filteredTokens = filterGlobalCommandTokens(tokens, usedGlobalFlags);
342
+ if (filteredTokens == null) {
343
+ return completeValues([], currentWord);
344
+ }
345
+ if (filteredTokens.length === 0) {
346
+ return completeValues(withHelpFlags([...COMPLETION_SHELLS], usedGlobalFlags), currentWord);
347
+ }
348
+ return completeValues([], currentWord);
349
+ }
350
+ function completeSimpleFlags(tokens, currentWord, usedGlobalFlags, commandFlags) {
351
+ let filteredTokens = filterGlobalCommandTokens(tokens, usedGlobalFlags);
352
+ if (filteredTokens == null) {
353
+ return completeValues([], currentWord);
354
+ }
355
+ let usedFlags = new Set();
356
+ for (let token of filteredTokens) {
357
+ if (!commandFlags.includes(token)) {
358
+ return completeValues([], currentWord);
359
+ }
360
+ usedFlags.add(token);
361
+ }
362
+ let availableFlags = commandFlags.filter((flag) => !usedFlags.has(flag));
363
+ return completeValues(withHelpFlags(availableFlags, usedGlobalFlags), currentWord);
364
+ }
365
+ function getTopLevelSuggestions(currentWord, usedFlags) {
366
+ let flags = [
367
+ ...(!usedFlags.has('-h') ? ['-h', '--help'] : []),
368
+ ...(!usedFlags.has('--no-color') ? ['--no-color'] : []),
369
+ ...(!usedFlags.has('-v') ? ['-v', '--version'] : []),
370
+ ];
371
+ if (currentWord.startsWith('-')) {
372
+ return flags;
373
+ }
374
+ return [...ROOT_COMMANDS, ...flags];
375
+ }
376
+ function withHelpFlags(values, usedGlobalFlags) {
377
+ return [
378
+ ...values,
379
+ ...(!usedGlobalFlags.has('-h') ? ['-h', '--help'] : []),
380
+ ...(!usedGlobalFlags.has('--no-color') ? ['--no-color'] : []),
381
+ ];
382
+ }
383
+ function filterGlobalCommandTokens(tokens, usedGlobalFlags) {
384
+ let filtered = [];
385
+ for (let token of tokens) {
386
+ if (token === '--no-color') {
387
+ usedGlobalFlags.add('--no-color');
388
+ continue;
389
+ }
390
+ if (token === '-h' || token === '--help') {
391
+ usedGlobalFlags.add('-h');
392
+ return null;
393
+ }
394
+ filtered.push(token);
395
+ }
396
+ return filtered;
397
+ }
398
+ function completeValues(values, currentWord) {
399
+ return {
400
+ mode: 'values',
401
+ values: values.filter((value) => value.startsWith(currentWord)),
402
+ };
403
+ }
404
+ function getTokensBeforeCursor(words, currentIndex) {
405
+ let startIndex = words[0] === 'remix' ? 1 : 0;
406
+ let endIndex = Math.max(startIndex, Math.min(currentIndex, words.length));
407
+ return words.slice(startIndex, endIndex);
408
+ }
@@ -0,0 +1,2 @@
1
+ export declare function resolveContainedPath(rootDir: string, relativePath: string): string;
2
+ //# sourceMappingURL=contained-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contained-path.d.ts","sourceRoot":"","sources":["../../src/lib/contained-path.ts"],"names":[],"mappings":"AAEA,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAUlF"}
@@ -0,0 +1,10 @@
1
+ import * as path from 'node:path';
2
+ export function resolveContainedPath(rootDir, relativePath) {
3
+ let resolvedRootDir = path.resolve(rootDir);
4
+ let resolvedPath = path.resolve(resolvedRootDir, relativePath);
5
+ let pathFromRoot = path.relative(resolvedRootDir, resolvedPath);
6
+ if (pathFromRoot === '' || (!pathFromRoot.startsWith('..') && !path.isAbsolute(pathFromRoot))) {
7
+ return resolvedPath;
8
+ }
9
+ throw new Error(`Resolved path escapes the allowed root: ${relativePath}`);
10
+ }
@@ -0,0 +1,14 @@
1
+ declare const OWNER_FILE_EXTENSIONS: readonly [".ts", ".tsx", ".js", ".jsx"];
2
+ export type OwnerFileExtension = (typeof OWNER_FILE_EXTENSIONS)[number];
3
+ export declare function getActionOwnerCandidates(segments: string[]): string[];
4
+ export declare function getControllerOwnerCandidates(segments: string[]): string[];
5
+ export declare function getRouteSubtreePath(segments: string[]): string;
6
+ export declare function getPreferredOwnerDisplayPath(candidates: string[]): string;
7
+ export declare function getOwnerCandidateForExtension(candidates: string[], extension: OwnerFileExtension): string | null;
8
+ export declare function getOwnerFileExtension(filePath: string): OwnerFileExtension | null;
9
+ export declare function toDiskSegment(segment: string): string;
10
+ export declare function isControllerEntryFileName(fileName: string): boolean;
11
+ export declare function getOwnerModuleBaseName(fileName: string): string | null;
12
+ export declare function isActionFileName(fileName: string): boolean;
13
+ export {};
14
+ //# sourceMappingURL=controller-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller-files.d.ts","sourceRoot":"","sources":["../../src/lib/controller-files.ts"],"names":[],"mappings":"AAEA,QAAA,MAAM,qBAAqB,yCAA0C,CAAA;AACrE,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEvE,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAIrE;AAED,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAIzE;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAE9D;AAED,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAGzE;AAED,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,MAAM,EAAE,EACpB,SAAS,EAAE,kBAAkB,GAC5B,MAAM,GAAG,IAAI,CAEf;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAEjF;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAYrD;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEnE;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQtE;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAS1D"}
@@ -0,0 +1,53 @@
1
+ import * as path from 'node:path';
2
+ const OWNER_FILE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx'];
3
+ export function getActionOwnerCandidates(segments) {
4
+ return OWNER_FILE_EXTENSIONS.map((extension) => normalizeRelativePath(path.join('app', 'controllers', `${path.join(...segments)}${extension}`)));
5
+ }
6
+ export function getControllerOwnerCandidates(segments) {
7
+ return OWNER_FILE_EXTENSIONS.map((extension) => normalizeRelativePath(path.join('app', 'controllers', ...segments, `controller${extension}`)));
8
+ }
9
+ export function getRouteSubtreePath(segments) {
10
+ return normalizeRelativePath(path.join('app', 'controllers', ...segments));
11
+ }
12
+ export function getPreferredOwnerDisplayPath(candidates) {
13
+ let tsxCandidate = candidates.find((candidate) => candidate.endsWith('.tsx'));
14
+ return tsxCandidate ?? candidates[0] ?? '';
15
+ }
16
+ export function getOwnerCandidateForExtension(candidates, extension) {
17
+ return candidates.find((candidate) => candidate.endsWith(extension)) ?? null;
18
+ }
19
+ export function getOwnerFileExtension(filePath) {
20
+ return OWNER_FILE_EXTENSIONS.find((extension) => filePath.endsWith(extension)) ?? null;
21
+ }
22
+ export function toDiskSegment(segment) {
23
+ let diskSegment = segment
24
+ .replace(/[\\/]+/g, '-')
25
+ .replace(/\.+/g, '-')
26
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
27
+ .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')
28
+ .toLowerCase()
29
+ .replace(/[^a-z0-9]+/g, '-')
30
+ .replace(/-+/g, '-')
31
+ .replace(/^-+|-+$/g, '');
32
+ return diskSegment.length === 0 ? 'route' : diskSegment;
33
+ }
34
+ export function isControllerEntryFileName(fileName) {
35
+ return OWNER_FILE_EXTENSIONS.some((extension) => fileName === `controller${extension}`);
36
+ }
37
+ export function getOwnerModuleBaseName(fileName) {
38
+ let extension = OWNER_FILE_EXTENSIONS.find((ownerExtension) => fileName.endsWith(ownerExtension));
39
+ if (extension == null) {
40
+ return null;
41
+ }
42
+ return fileName.slice(0, -extension.length);
43
+ }
44
+ export function isActionFileName(fileName) {
45
+ let baseName = getOwnerModuleBaseName(fileName);
46
+ return (baseName != null &&
47
+ baseName !== 'controller' &&
48
+ !baseName.endsWith('.test') &&
49
+ !baseName.endsWith('.spec'));
50
+ }
51
+ function normalizeRelativePath(filePath) {
52
+ return filePath.split(path.sep).join('/');
53
+ }
@@ -0,0 +1,41 @@
1
+ import type { RouteOwnerKind, RouteTreeNodeKind } from './route-map.ts';
2
+ export interface OwnershipRouteNode {
3
+ children: OwnershipRouteNode[];
4
+ key: string;
5
+ kind: RouteTreeNodeKind;
6
+ method?: string;
7
+ name: string;
8
+ }
9
+ export interface ControllerDirectoryScan {
10
+ actionEntryPaths: Set<string>;
11
+ controllerEntryPaths: Set<string>;
12
+ rootDirectoryPaths: Set<string>;
13
+ routeLocalFilePaths: Set<string>;
14
+ }
15
+ export interface OwnedSubtreePlan {
16
+ alternateCandidates: string[];
17
+ alternateDisplayPath: string;
18
+ entryCandidates: string[];
19
+ entryDisplayPath: string;
20
+ kind: RouteOwnerKind;
21
+ routeName: string;
22
+ subtreePath: string;
23
+ }
24
+ export interface OwnedSubtree extends OwnedSubtreePlan {
25
+ actualAlternatePath: string | null;
26
+ actualAlternatePaths: string[];
27
+ actualEntryPath: string | null;
28
+ actualEntryPaths: string[];
29
+ claimedFilePaths: string[];
30
+ claimedRouteLocalFilePaths: string[];
31
+ }
32
+ export interface ControllerOwnership {
33
+ orphanActionPaths: string[];
34
+ orphanControllerPaths: string[];
35
+ orphanRouteDirectoryPaths: string[];
36
+ scan: ControllerDirectoryScan;
37
+ subtrees: OwnedSubtree[];
38
+ }
39
+ export declare function inspectControllerOwnership(appRoot: string, tree: OwnershipRouteNode[]): Promise<ControllerOwnership>;
40
+ export declare function buildOwnedSubtrees(tree: OwnershipRouteNode[], parentSegments?: string[], subtrees?: OwnedSubtreePlan[]): OwnedSubtreePlan[];
41
+ //# sourceMappingURL=controller-ownership.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller-ownership.d.ts","sourceRoot":"","sources":["../../src/lib/controller-ownership.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAEvE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,kBAAkB,EAAE,CAAA;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,iBAAiB,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,uBAAuB;IACtC,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC7B,oBAAoB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACjC,kBAAkB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC/B,mBAAmB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CACjC;AAED,MAAM,WAAW,gBAAgB;IAC/B,mBAAmB,EAAE,MAAM,EAAE,CAAA;IAC7B,oBAAoB,EAAE,MAAM,CAAA;IAC5B,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,gBAAgB,EAAE,MAAM,CAAA;IACxB,IAAI,EAAE,cAAc,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,YAAa,SAAQ,gBAAgB;IACpD,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,oBAAoB,EAAE,MAAM,EAAE,CAAA;IAC9B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,0BAA0B,EAAE,MAAM,EAAE,CAAA;CACrC;AAED,MAAM,WAAW,mBAAmB;IAClC,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B,qBAAqB,EAAE,MAAM,EAAE,CAAA;IAC/B,yBAAyB,EAAE,MAAM,EAAE,CAAA;IACnC,IAAI,EAAE,uBAAuB,CAAA;IAC7B,QAAQ,EAAE,YAAY,EAAE,CAAA;CACzB;AAED,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,kBAAkB,EAAE,GACzB,OAAO,CAAC,mBAAmB,CAAC,CAY9B;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,kBAAkB,EAAE,EAC1B,cAAc,GAAE,MAAM,EAAO,EAC7B,QAAQ,GAAE,gBAAgB,EAAO,GAChC,gBAAgB,EAAE,CAwCpB"}