@hydranium/cli 1.0.0-next.39 → 1.0.0-next.390

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 (339) hide show
  1. package/README.md +102 -204
  2. package/bin/hydranium-cli.js +13 -0
  3. package/heap-analysis/heap/core/load.mjs +2 -2
  4. package/heap-analysis/heap/langium/langium.classifier.mjs +22 -11
  5. package/lib/cli-version.js.map +1 -1
  6. package/lib/cli.js +7 -2
  7. package/lib/cli.js.map +1 -1
  8. package/lib/commands/analyze-heap-args.d.ts.map +1 -1
  9. package/lib/commands/analyze-heap-args.js +1 -2
  10. package/lib/commands/analyze-heap-args.js.map +1 -1
  11. package/lib/commands/analyze-heap.d.ts +3 -0
  12. package/lib/commands/analyze-heap.d.ts.map +1 -1
  13. package/lib/commands/analyze-heap.js +2 -1
  14. package/lib/commands/analyze-heap.js.map +1 -1
  15. package/lib/commands/ast-ground-truth-args.d.ts +3 -2
  16. package/lib/commands/ast-ground-truth-args.d.ts.map +1 -1
  17. package/lib/commands/ast-ground-truth-args.js +11 -9
  18. package/lib/commands/ast-ground-truth-args.js.map +1 -1
  19. package/lib/commands/ast-ground-truth-driver.js +4 -2
  20. package/lib/commands/ast-ground-truth-driver.js.map +1 -1
  21. package/lib/commands/ast-ground-truth.js +1 -1
  22. package/lib/commands/ast-ground-truth.js.map +1 -1
  23. package/lib/commands/client-session.d.ts +17 -0
  24. package/lib/commands/client-session.d.ts.map +1 -0
  25. package/lib/commands/client-session.js +27 -0
  26. package/lib/commands/client-session.js.map +1 -0
  27. package/lib/commands/create-args.d.ts +17 -0
  28. package/lib/commands/create-args.d.ts.map +1 -0
  29. package/lib/commands/create-args.js +53 -0
  30. package/lib/commands/create-args.js.map +1 -0
  31. package/lib/commands/create.d.ts +38 -0
  32. package/lib/commands/create.d.ts.map +1 -0
  33. package/lib/commands/create.js +43 -0
  34. package/lib/commands/create.js.map +1 -0
  35. package/lib/commands/delete-args.d.ts +17 -0
  36. package/lib/commands/delete-args.d.ts.map +1 -0
  37. package/lib/commands/delete-args.js +49 -0
  38. package/lib/commands/delete-args.js.map +1 -0
  39. package/lib/commands/delete.d.ts +30 -0
  40. package/lib/commands/delete.d.ts.map +1 -0
  41. package/lib/commands/delete.js +32 -0
  42. package/lib/commands/delete.js.map +1 -0
  43. package/lib/commands/generate-ast-builder.d.ts.map +1 -1
  44. package/lib/commands/generate-ast-builder.js +1 -10
  45. package/lib/commands/generate-ast-builder.js.map +1 -1
  46. package/lib/commands/generate-languages.d.ts +35 -0
  47. package/lib/commands/generate-languages.d.ts.map +1 -0
  48. package/lib/commands/generate-languages.js +105 -0
  49. package/lib/commands/generate-languages.js.map +1 -0
  50. package/lib/commands/generate-transfer-builder.d.ts +33 -0
  51. package/lib/commands/generate-transfer-builder.d.ts.map +1 -0
  52. package/lib/commands/generate-transfer-builder.js +86 -0
  53. package/lib/commands/generate-transfer-builder.js.map +1 -0
  54. package/lib/commands/generate-transfer-model-args.d.ts.map +1 -1
  55. package/lib/commands/generate-transfer-model-args.js +20 -5
  56. package/lib/commands/generate-transfer-model-args.js.map +1 -1
  57. package/lib/commands/generate-transfer-model-config.d.ts.map +1 -1
  58. package/lib/commands/generate-transfer-model-config.js +8 -3
  59. package/lib/commands/generate-transfer-model-config.js.map +1 -1
  60. package/lib/commands/generate-transfer-model.d.ts +40 -9
  61. package/lib/commands/generate-transfer-model.d.ts.map +1 -1
  62. package/lib/commands/generate-transfer-model.js +219 -67
  63. package/lib/commands/generate-transfer-model.js.map +1 -1
  64. package/lib/commands/generated-module-path.d.ts +16 -0
  65. package/lib/commands/generated-module-path.d.ts.map +1 -0
  66. package/lib/commands/generated-module-path.js +21 -0
  67. package/lib/commands/generated-module-path.js.map +1 -0
  68. package/lib/commands/harness-args.d.ts +44 -42
  69. package/lib/commands/harness-args.d.ts.map +1 -1
  70. package/lib/commands/harness-args.js +109 -27
  71. package/lib/commands/harness-args.js.map +1 -1
  72. package/lib/commands/headless-harness.d.ts +37 -20
  73. package/lib/commands/headless-harness.d.ts.map +1 -1
  74. package/lib/commands/headless-harness.js +71 -19
  75. package/lib/commands/headless-harness.js.map +1 -1
  76. package/lib/commands/init-args.d.ts +2 -0
  77. package/lib/commands/init-args.d.ts.map +1 -1
  78. package/lib/commands/init-args.js +74 -31
  79. package/lib/commands/init-args.js.map +1 -1
  80. package/lib/commands/init-hosts.d.ts +24 -0
  81. package/lib/commands/init-hosts.d.ts.map +1 -0
  82. package/lib/commands/init-hosts.js +37 -0
  83. package/lib/commands/init-hosts.js.map +1 -0
  84. package/lib/commands/init-prompt.d.ts +3 -3
  85. package/lib/commands/init-prompt.d.ts.map +1 -1
  86. package/lib/commands/init-prompt.js +4 -5
  87. package/lib/commands/init-prompt.js.map +1 -1
  88. package/lib/commands/init-templates.d.ts +26 -14
  89. package/lib/commands/init-templates.d.ts.map +1 -1
  90. package/lib/commands/init-templates.js +2989 -746
  91. package/lib/commands/init-templates.js.map +1 -1
  92. package/lib/commands/init-wizard.d.ts +3 -0
  93. package/lib/commands/init-wizard.d.ts.map +1 -1
  94. package/lib/commands/init-wizard.js +46 -31
  95. package/lib/commands/init-wizard.js.map +1 -1
  96. package/lib/commands/init-workspace.d.ts +13 -11
  97. package/lib/commands/init-workspace.d.ts.map +1 -1
  98. package/lib/commands/init-workspace.js +21 -7
  99. package/lib/commands/init-workspace.js.map +1 -1
  100. package/lib/commands/init.d.ts +58 -22
  101. package/lib/commands/init.d.ts.map +1 -1
  102. package/lib/commands/init.js +206 -48
  103. package/lib/commands/init.js.map +1 -1
  104. package/lib/commands/kebab.d.ts +15 -0
  105. package/lib/commands/kebab.d.ts.map +1 -0
  106. package/lib/commands/kebab.js +17 -0
  107. package/lib/commands/kebab.js.map +1 -0
  108. package/lib/commands/lint-grammar-args.d.ts +3 -2
  109. package/lib/commands/lint-grammar-args.d.ts.map +1 -1
  110. package/lib/commands/lint-grammar-args.js +13 -10
  111. package/lib/commands/lint-grammar-args.js.map +1 -1
  112. package/lib/commands/lint-grammar-driver.js +2 -1
  113. package/lib/commands/lint-grammar-driver.js.map +1 -1
  114. package/lib/commands/lint-grammar-report.js.map +1 -1
  115. package/lib/commands/lint-grammar.js +1 -1
  116. package/lib/commands/lint-grammar.js.map +1 -1
  117. package/lib/commands/measure-memory-args.d.ts +3 -2
  118. package/lib/commands/measure-memory-args.d.ts.map +1 -1
  119. package/lib/commands/measure-memory-args.js +22 -11
  120. package/lib/commands/measure-memory-args.js.map +1 -1
  121. package/lib/commands/measure-memory-driver.js +5 -3
  122. package/lib/commands/measure-memory-driver.js.map +1 -1
  123. package/lib/commands/measure-memory.js +1 -1
  124. package/lib/commands/measure-memory.js.map +1 -1
  125. package/lib/commands/model-docs-args.d.ts +4 -3
  126. package/lib/commands/model-docs-args.d.ts.map +1 -1
  127. package/lib/commands/model-docs-args.js +12 -10
  128. package/lib/commands/model-docs-args.js.map +1 -1
  129. package/lib/commands/model-docs-driver.js +2 -1
  130. package/lib/commands/model-docs-driver.js.map +1 -1
  131. package/lib/commands/model-docs.js +1 -1
  132. package/lib/commands/model-docs.js.map +1 -1
  133. package/lib/commands/projects-args.d.ts.map +1 -1
  134. package/lib/commands/projects-args.js +5 -5
  135. package/lib/commands/projects-args.js.map +1 -1
  136. package/lib/commands/projects.d.ts +3 -4
  137. package/lib/commands/projects.d.ts.map +1 -1
  138. package/lib/commands/projects.js +2 -2
  139. package/lib/commands/projects.js.map +1 -1
  140. package/lib/commands/query-args.d.ts.map +1 -1
  141. package/lib/commands/query-args.js +6 -5
  142. package/lib/commands/query-args.js.map +1 -1
  143. package/lib/commands/query.d.ts +6 -5
  144. package/lib/commands/query.d.ts.map +1 -1
  145. package/lib/commands/query.js +5 -4
  146. package/lib/commands/query.js.map +1 -1
  147. package/lib/commands/reflect-args.d.ts +3 -2
  148. package/lib/commands/reflect-args.d.ts.map +1 -1
  149. package/lib/commands/reflect-args.js +13 -10
  150. package/lib/commands/reflect-args.js.map +1 -1
  151. package/lib/commands/reflect-driver.js +2 -1
  152. package/lib/commands/reflect-driver.js.map +1 -1
  153. package/lib/commands/reflect-report.js.map +1 -1
  154. package/lib/commands/reflect.js +1 -1
  155. package/lib/commands/reflect.js.map +1 -1
  156. package/lib/commands/save-args.d.ts.map +1 -1
  157. package/lib/commands/save-args.js +7 -4
  158. package/lib/commands/save-args.js.map +1 -1
  159. package/lib/commands/save.d.ts +8 -4
  160. package/lib/commands/save.d.ts.map +1 -1
  161. package/lib/commands/save.js +12 -23
  162. package/lib/commands/save.js.map +1 -1
  163. package/lib/commands/validate-args.d.ts +3 -2
  164. package/lib/commands/validate-args.d.ts.map +1 -1
  165. package/lib/commands/validate-args.js +13 -10
  166. package/lib/commands/validate-args.js.map +1 -1
  167. package/lib/commands/validate-driver.js +2 -1
  168. package/lib/commands/validate-driver.js.map +1 -1
  169. package/lib/commands/validate-report.js.map +1 -1
  170. package/lib/commands/validate.js +1 -1
  171. package/lib/commands/validate.js.map +1 -1
  172. package/lib/commands/watch-args.d.ts.map +1 -1
  173. package/lib/commands/watch-args.js +6 -4
  174. package/lib/commands/watch-args.js.map +1 -1
  175. package/lib/commands/watch.d.ts +3 -4
  176. package/lib/commands/watch.d.ts.map +1 -1
  177. package/lib/commands/watch.js +5 -2
  178. package/lib/commands/watch.js.map +1 -1
  179. package/lib/driver-heap.d.ts +52 -0
  180. package/lib/driver-heap.d.ts.map +1 -0
  181. package/lib/driver-heap.js +51 -0
  182. package/lib/driver-heap.js.map +1 -0
  183. package/lib/index.d.ts +2 -0
  184. package/lib/index.d.ts.map +1 -1
  185. package/lib/index.js +2 -0
  186. package/lib/index.js.map +1 -1
  187. package/lib/log-level.d.ts +21 -11
  188. package/lib/log-level.d.ts.map +1 -1
  189. package/lib/log-level.js +25 -14
  190. package/lib/log-level.js.map +1 -1
  191. package/lib/spawn-data-server.d.ts +9 -4
  192. package/lib/spawn-data-server.d.ts.map +1 -1
  193. package/lib/spawn-data-server.js +5 -4
  194. package/lib/spawn-data-server.js.map +1 -1
  195. package/lib/stderr-connection-logger.d.ts +12 -0
  196. package/lib/stderr-connection-logger.d.ts.map +1 -0
  197. package/lib/stderr-connection-logger.js +16 -0
  198. package/lib/stderr-connection-logger.js.map +1 -0
  199. package/lib/testing/echo-server.js +9 -1
  200. package/lib/testing/echo-server.js.map +1 -1
  201. package/package.json +90 -39
  202. package/src/cli.ts +7 -2
  203. package/src/commands/analyze-heap-args.ts +1 -2
  204. package/src/commands/analyze-heap.ts +4 -1
  205. package/src/commands/ast-ground-truth-args.ts +15 -12
  206. package/src/commands/ast-ground-truth-driver.ts +4 -2
  207. package/src/commands/ast-ground-truth.ts +1 -1
  208. package/src/commands/client-session.ts +33 -0
  209. package/src/commands/create-args.ts +68 -0
  210. package/src/commands/create.ts +83 -0
  211. package/src/commands/delete-args.ts +64 -0
  212. package/src/commands/delete.ts +61 -0
  213. package/src/commands/generate-ast-builder.ts +1 -11
  214. package/src/commands/generate-languages.ts +132 -0
  215. package/src/commands/generate-transfer-builder.ts +101 -0
  216. package/src/commands/generate-transfer-model-args.ts +20 -5
  217. package/src/commands/generate-transfer-model-config.ts +8 -3
  218. package/src/commands/generate-transfer-model.ts +291 -65
  219. package/src/commands/generated-module-path.ts +22 -0
  220. package/src/commands/harness-args.ts +99 -31
  221. package/src/commands/headless-harness.ts +89 -28
  222. package/src/commands/init-args.ts +76 -31
  223. package/src/commands/init-hosts.ts +51 -0
  224. package/src/commands/init-prompt.ts +5 -6
  225. package/src/commands/init-templates.ts +3161 -759
  226. package/src/commands/init-wizard.ts +55 -31
  227. package/src/commands/init-workspace.ts +31 -16
  228. package/src/commands/init.ts +266 -63
  229. package/src/commands/kebab.ts +17 -0
  230. package/src/commands/lint-grammar-args.ts +17 -13
  231. package/src/commands/lint-grammar-driver.ts +2 -1
  232. package/src/commands/lint-grammar.ts +1 -1
  233. package/src/commands/measure-memory-args.ts +27 -14
  234. package/src/commands/measure-memory-driver.ts +5 -3
  235. package/src/commands/measure-memory.ts +1 -1
  236. package/src/commands/model-docs-args.ts +16 -13
  237. package/src/commands/model-docs-driver.ts +2 -1
  238. package/src/commands/model-docs.ts +1 -1
  239. package/src/commands/projects-args.ts +5 -4
  240. package/src/commands/projects.ts +4 -6
  241. package/src/commands/query-args.ts +6 -4
  242. package/src/commands/query.ts +9 -9
  243. package/src/commands/reflect-args.ts +17 -13
  244. package/src/commands/reflect-driver.ts +2 -1
  245. package/src/commands/reflect.ts +1 -1
  246. package/src/commands/save-args.ts +7 -3
  247. package/src/commands/save.ts +24 -27
  248. package/src/commands/validate-args.ts +17 -13
  249. package/src/commands/validate-driver.ts +2 -1
  250. package/src/commands/validate.ts +1 -1
  251. package/src/commands/watch-args.ts +6 -3
  252. package/src/commands/watch.ts +7 -6
  253. package/src/driver-heap.ts +65 -0
  254. package/src/index.ts +2 -0
  255. package/src/log-level.ts +42 -14
  256. package/src/spawn-data-server.ts +17 -5
  257. package/src/stderr-connection-logger.ts +18 -0
  258. package/src/testing/echo-server.ts +11 -2
  259. package/templates/client/gitignore +3 -0
  260. package/templates/client/src/__GRAMMAR_ID__-diagram-module.ts +82 -0
  261. package/templates/editorconfig +15 -0
  262. package/templates/gitignore +1 -0
  263. package/templates/host-browser/esbuild.mjs +82 -0
  264. package/templates/host-browser/gitignore +4 -0
  265. package/templates/host-browser/hydranium-mark.svg +40 -0
  266. package/templates/host-browser/index.html +287 -0
  267. package/templates/host-browser/playwright.config.mts +24 -0
  268. package/templates/host-browser/src/data-status.ts +15 -0
  269. package/templates/host-browser/src/diagram-save.ts +60 -0
  270. package/templates/host-browser/src/diagram.ts +121 -0
  271. package/templates/host-browser/src/editor.ts +102 -0
  272. package/templates/host-browser/src/log.ts +14 -0
  273. package/templates/host-browser/src/monaco-editor-core-worker.d.ts +7 -0
  274. package/templates/host-browser/src/monaco-editor-worker.ts +10 -0
  275. package/templates/host-browser/src/posix-path-shim.ts +23 -0
  276. package/templates/host-browser/src/shown-file.ts +61 -0
  277. package/templates/host-browser/src/workspace.ts +5 -0
  278. package/templates/host-browser/tsconfig.e2e.json +16 -0
  279. package/templates/host-browser/tsconfig.page.json +16 -0
  280. package/templates/host-browser/tsconfig.worker.json +16 -0
  281. package/templates/host-theia-browser/esbuild.mjs +24 -0
  282. package/templates/host-theia-browser/gitignore +9 -0
  283. package/templates/host-theia-browser/playwright.config.mts +42 -0
  284. package/templates/host-theia-browser/start.mjs +50 -0
  285. package/templates/host-theia-browser/tsconfig.e2e.json +16 -0
  286. package/templates/host-theia-electron/esbuild.mjs +27 -0
  287. package/templates/host-theia-electron/gitignore +8 -0
  288. package/templates/host-theia-electron/playwright.config.mts +12 -0
  289. package/templates/host-theia-electron/start.mjs +47 -0
  290. package/templates/host-theia-electron/tsconfig.e2e.json +16 -0
  291. package/templates/host-vscode/esbuild.mjs +38 -0
  292. package/templates/host-vscode/gitignore +7 -0
  293. package/templates/host-vscode/playwright.config.mts +14 -0
  294. package/templates/host-vscode/src/__GRAMMAR_ID__-diagram-editor.ts +19 -0
  295. package/templates/host-vscode/src/show-model-command.ts +24 -0
  296. package/templates/host-vscode/src/webview/__GRAMMAR_ID__-diagram.ts +18 -0
  297. package/templates/host-vscode/src/webview/diagram.css +40 -0
  298. package/templates/host-vscode/start.mjs +22 -0
  299. package/templates/host-vscode/test/install-vscode.mts +21 -0
  300. package/templates/host-vscode/test/vscode-version.mts +10 -0
  301. package/templates/host-vscode/tsconfig.e2e.json +17 -0
  302. package/templates/host-vscode/tsconfig.json +19 -0
  303. package/templates/host-vscode/tsconfig.webview.json +17 -0
  304. package/templates/oxlintrc.json +4 -0
  305. package/templates/protocol/gitignore +3 -0
  306. package/templates/protocol/src/__GRAMMAR_ID__-diagram-types.ts +47 -0
  307. package/templates/server/gitignore +6 -0
  308. package/templates/server/src/glsp/__GRAMMAR_ID__/create-node-operation-handler.ts +62 -0
  309. package/templates/server/src/glsp/__GRAMMAR_ID__/delete-operation-handler.ts +63 -0
  310. package/templates/server/src/glsp/__GRAMMAR_ID__/gmodel-factory.ts +144 -0
  311. package/templates/server/src/glsp/__GRAMMAR_ID__/state.ts +18 -0
  312. package/templates/server/src/glsp/__GRAMMAR_ID__/storage.ts +16 -0
  313. package/templates/server/src/glsp/__GRAMMAR_ID__/submission-handler.ts +24 -0
  314. package/templates/server/src/grammar/common.langium +12 -0
  315. package/templates/server/src/language-server/__GRAMMAR_ID__-serializer.ts +53 -0
  316. package/templates/server/src/language-server/__GRAMMAR_ID__-validation.ts +30 -0
  317. package/templates/server/src/language-server/ast.ts +23 -0
  318. package/templates/server/src/node/services.ts +16 -0
  319. package/templates/server/test/__GRAMMAR_ID__-diagram.test.ts +403 -0
  320. package/templates/server/test/tsconfig.json +4 -0
  321. package/templates/server/tsconfig.test.json +10 -0
  322. package/templates/server/vitest.config.ts +14 -0
  323. package/templates/theia/gitignore +3 -0
  324. package/templates/theia/src/browser/__GRAMMAR_ID__-diagram-frontend-module.ts +65 -0
  325. package/templates/theia/src/browser/__PROJECT_ID__-connection-preload-module.ts +15 -0
  326. package/templates/theia/src/browser/__PROJECT_ID__-data-connection.ts +15 -0
  327. package/templates/theia/src/browser/__PROJECT_ID__-data-port.ts +11 -0
  328. package/templates/theia/src/browser/__PROJECT_ID__-glsp-client-contribution.ts +13 -0
  329. package/templates/theia/src/browser/__PROJECT_ID__-show-model-command.ts +51 -0
  330. package/templates/theia/src/common/__PROJECT_ID__-glsp-contribution.ts +3 -0
  331. package/templates/theia/src/node/__PROJECT_ID__-connection-backend-module.ts +12 -0
  332. package/templates/theia/src/node/__PROJECT_ID__-data-backend-module.ts +15 -0
  333. package/templates/theia/src/node/__PROJECT_ID__-glsp-backend-module.ts +16 -0
  334. package/templates/theia/style/diagram.css +20 -0
  335. package/templates/theia/tsconfig.json +24 -0
  336. package/templates/vscode-servers/gitignore +4 -0
  337. package/templates/vscode-servers/tsconfig.json +19 -0
  338. package/templates/workspace/nodes.__EXTENSION__ +5 -0
  339. package/templates/workspace/references.__EXTENSION__ +2 -0
@@ -55,8 +55,10 @@
55
55
  */
56
56
 
57
57
  import * as path from 'node:path';
58
- import { DEFAULT_INIT_HEADS, INIT_HEADS, type InitHead, isNonEmptyDir, kebab } from './init.js';
59
- import { InitWizardCancelled, OPTIONAL_HEAD_CHOICES, type PromptPort } from './init-prompt.js';
58
+ import { DEFAULT_INIT_HEADS, INIT_HEADS, type InitHead, initMembers, isNonEmptyDir, isUsableExtension, memberPlacements } from './init.js';
59
+ import { editingHeads, INIT_HOSTS, type InitHost } from './init-hosts.js';
60
+ import { kebab } from './kebab.js';
61
+ import { HEAD_CHOICES, InitWizardCancelled, type PromptPort } from './init-prompt.js';
60
62
  import { type WorkspaceDetection } from './init-workspace.js';
61
63
 
62
64
  /** One grammar as the wizard collected it. */
@@ -77,6 +79,8 @@ export interface InitAnswers {
77
79
  readonly name: string;
78
80
  /** The protocol heads to start. */
79
81
  readonly heads: readonly InitHead[];
82
+ /** The host applications to emit around the server. */
83
+ readonly hosts: readonly InitHost[];
80
84
  /** The grammars, in the order they were given. */
81
85
  readonly grammars: readonly InitGrammarAnswer[];
82
86
  /** Scaffold into a non-empty directory anyway. */
@@ -117,6 +121,9 @@ export function composeInitArgv(answers: InitAnswers): string[] {
117
121
  if (answers.heads.join(',') !== DEFAULT_INIT_HEADS.join(',')) {
118
122
  argv.push('--heads', answers.heads.join(','));
119
123
  }
124
+ if (answers.hosts.length > 0) {
125
+ argv.push('--hosts', answers.hosts.join(','));
126
+ }
120
127
  const several = answers.grammars.length > 1;
121
128
  for (const grammar of answers.grammars) {
122
129
  // A lone grammar named after the project, taking the derived extension, is
@@ -158,13 +165,13 @@ export function formatCommand(argv: readonly string[]): string {
158
165
  /** Validate a file extension, and reject one another grammar already claims. */
159
166
  function extensionProblem(value: string, taken: ReadonlySet<string>): string | undefined {
160
167
  const extension = value.replace(/^\./, '');
161
- if (!/^[A-Za-z0-9][A-Za-z0-9-]*$/.test(extension)) {
168
+ if (!isUsableExtension(extension)) {
162
169
  return `'${value}' is not a usable file extension.`;
163
170
  }
164
171
  // Checked here rather than left to the scaffolder so the answer is corrected
165
172
  // while the grammar that owns it is still on screen. Langium routes documents
166
173
  // to a language BY extension, so a duplicate is a silent mis-route.
167
- return taken.has(extension) ? `'.${extension}' is already claimed by another grammar.` : undefined;
174
+ return taken.has(extension.toLowerCase()) ? `'.${extension}' is already claimed by another grammar.` : undefined;
168
175
  }
169
176
 
170
177
  /**
@@ -198,31 +205,42 @@ async function askGrammar(
198
205
  return { name, extension: extension.replace(/^\./, ''), diagram: false };
199
206
  }
200
207
 
208
+ /** Ask for the protocol head set, in composition order whatever order they were picked in. */
209
+ async function askHeads(prompt: PromptPort): Promise<InitHead[]> {
210
+ const chosen = await prompt.multiselect({ message: 'Protocol heads', choices: HEAD_CHOICES, initialValues: DEFAULT_INIT_HEADS });
211
+ return INIT_HEADS.filter(head => chosen.includes(head));
212
+ }
213
+
214
+ /** What the wizard asks about each host. */
215
+ const HOST_QUESTIONS: Record<InitHost, string> = {
216
+ browser: 'Add a browser host (every head in a web worker, no backend)?',
217
+ vscode: 'Add a VS Code extension (the language client, Show Model with the data head, and a custom editor per diagram)?',
218
+ 'theia-browser':
219
+ 'Add a Theia browser application (the language client, Show Model with the data head, and a diagram editor per diagram)?',
220
+ 'theia-electron': 'Add a Theia Electron application (the same as the Theia browser application, in a desktop window)?'
221
+ };
222
+
201
223
  /**
202
- * Ask for the protocol head set.
203
- *
204
- * `lsp` is not offered, it is stated: it owns the workspace, the build pipeline
205
- * and the shared tier the other heads read through, so a project without it has
206
- * nothing for them to serve. Presenting it as a checkbox would offer a choice
207
- * the scaffolder then refuses.
224
+ * Ask for each host the head set can run, one yes/no each. A host none of
225
+ * whose editing heads is on is not offered: `init` would refuse it.
208
226
  */
209
- async function askHeads(prompt: PromptPort): Promise<InitHead[]> {
210
- const optional = await prompt.multiselect({
211
- message: 'Protocol heads — lsp is always included',
212
- choices: OPTIONAL_HEAD_CHOICES,
213
- initialValues: DEFAULT_INIT_HEADS.filter((head): head is Exclude<InitHead, 'lsp'> => head !== 'lsp')
214
- });
215
- const chosen = new Set<InitHead>(['lsp', ...optional]);
216
- return INIT_HEADS.filter(head => chosen.has(head));
227
+ async function askHosts(prompt: PromptPort, heads: readonly InitHead[]): Promise<InitHost[]> {
228
+ const hosts: InitHost[] = [];
229
+ for (const host of INIT_HOSTS.filter(candidate => editingHeads(candidate).some(head => heads.includes(head)))) {
230
+ if (await prompt.confirm({ message: HOST_QUESTIONS[host], initialValue: false })) {
231
+ hosts.push(host);
232
+ }
233
+ }
234
+ return hosts;
217
235
  }
218
236
 
219
237
  /**
220
238
  * Mark the grammar a scaffolded diagram edits.
221
239
  *
222
- * Only a real question with `glsp` on AND several grammars: a diagram type
223
- * binds exactly ONE grammar, and with a single grammar the scaffolder derives
224
- * that answer already — so asking would offer a choice whose "no" it would
225
- * silently overrule.
240
+ * Only a real question with `glsp` on AND several grammars: the scaffolded
241
+ * diagram is typed over one grammar's model, and with a single grammar the
242
+ * scaffolder derives that answer already — so asking would offer a choice
243
+ * whose "no" it would silently overrule.
226
244
  */
227
245
  async function askDiagramGrammar(
228
246
  prompt: PromptPort,
@@ -263,15 +281,18 @@ async function confirmOccupiedTarget(prompt: PromptPort, targetDir: string, isOc
263
281
  /** Ask the workspace questions, or answer them "no" when there is no workspace to join. */
264
282
  async function askWorkspaceMembership(
265
283
  prompt: PromptPort,
266
- detection: WorkspaceDetection | undefined
284
+ detection: WorkspaceDetection | undefined,
285
+ heads: readonly InitHead[],
286
+ hosts: readonly InitHost[]
267
287
  ): Promise<{ monorepo: boolean; scope?: string }> {
268
288
  if (detection === undefined) {
269
289
  return { monorepo: false };
270
290
  }
291
+ const uncovered = memberPlacements(detection, initMembers(heads, hosts)).filter(placement => placement.coveredBy === undefined);
271
292
  const covered =
272
- detection.coveredBy === undefined
273
- ? `The root manifest has no entry covering it, so one is printed for you to add.`
274
- : `Already covered by the "${detection.coveredBy}" workspaces entry.`;
293
+ uncovered.length === 0
294
+ ? 'Its packages are already covered by the workspaces entries.'
295
+ : `The root manifest has no entry covering ${uncovered.map(placement => placement.path).join(', ')}, so ${uncovered.length === 1 ? 'one is' : 'they are'} printed for you to add.`;
275
296
  // The placement is named, not just the root. The root alone reads as "this
276
297
  // ran somewhere I did not ask for" whenever the command was issued from a
277
298
  // different directory than the target, which is the normal case.
@@ -310,9 +331,11 @@ async function askWorkspaceMembership(
310
331
  */
311
332
  async function askPackaging(
312
333
  prompt: PromptPort,
313
- detection: WorkspaceDetection | undefined
334
+ detection: WorkspaceDetection | undefined,
335
+ heads: readonly InitHead[],
336
+ hosts: readonly InitHost[]
314
337
  ): Promise<{ monorepo: boolean; scope?: string; public: boolean }> {
315
- const membership = await askWorkspaceMembership(prompt, detection);
338
+ const membership = await askWorkspaceMembership(prompt, detection, heads, hosts);
316
339
  const isPublic = await prompt.confirm({ message: 'Publishable to npm (the manifest says UNLICENSED)?', initialValue: false });
317
340
  return { ...membership, public: isPublic };
318
341
  }
@@ -353,6 +376,7 @@ export async function runInitWizard(
353
376
  });
354
377
 
355
378
  const heads = await askHeads(prompt);
379
+ const hosts = await askHosts(prompt, heads);
356
380
 
357
381
  // One grammar at a time, each with its own settings, then an explicit "add
358
382
  // another" — so the single-grammar case costs two keystrokes and the
@@ -364,13 +388,13 @@ export async function runInitWizard(
364
388
  const grammar = await askGrammar(prompt, grammars.length, grammars.length === 0 ? name : undefined, takenNames, takenExtensions);
365
389
  grammars.push(grammar);
366
390
  takenNames.add(grammar.name);
367
- takenExtensions.add(grammar.extension);
391
+ takenExtensions.add(grammar.extension.toLowerCase());
368
392
  } while (await prompt.confirm({ message: 'Add another grammar?', initialValue: false }));
369
393
 
370
394
  const withDiagram = await askDiagramGrammar(prompt, heads, grammars);
371
- const packaging = await askPackaging(prompt, detect(targetDir));
395
+ const packaging = await askPackaging(prompt, detect(targetDir), heads, hosts);
372
396
 
373
- const argv = composeInitArgv({ targetDir, name, heads, grammars: withDiagram, force, ...packaging });
397
+ const argv = composeInitArgv({ targetDir, name, heads, hosts, grammars: withDiagram, force, ...packaging });
374
398
  // Echoed as the LAST thing before the scaffold runs, because it is the
375
399
  // artefact the session produces: everything above is how it was reached.
376
400
  prompt.outro(formatCommand(argv));
@@ -169,14 +169,6 @@ export interface WorkspaceDetection {
169
169
  readonly workspaces: readonly string[];
170
170
  /** POSIX path of the target relative to {@link rootDir}, e.g. `packages/foo`. */
171
171
  readonly targetPath: string;
172
- /**
173
- * The `workspaces` glob already covering {@link targetPath}, if any.
174
- *
175
- * Absent means the root manifest needs a new entry — which is why this is
176
- * computed per target rather than assumed: a `packages/*` glob covers a new
177
- * package for free, while a repo that lists its examples one by one does not.
178
- */
179
- readonly coveredBy?: string;
180
172
  /** The npm scope the sibling packages agree on (`@acme`), when they agree. */
181
173
  readonly scope?: string;
182
174
  /**
@@ -186,10 +178,14 @@ export interface WorkspaceDetection {
186
178
  readonly baseTsconfig?: string;
187
179
  /** That tsconfig's `compilerOptions`, so the emitted one can drop what it inherits. */
188
180
  readonly baseCompilerOptions?: Readonly<Record<string, JsonValue>>;
189
- /** The root prettier config's `printWidth`, so emitted sources wrap where the repo wraps. */
181
+ /** The root formatter config's `printWidth`, so emitted sources wrap where the repo wraps. */
190
182
  readonly printWidth?: number;
191
183
  /** Filename of the root eslint config, when there is one. Absent means the repo does not lint. */
192
184
  readonly eslintConfig?: string;
185
+ /** Filename of the root Oxlint config, when present. */
186
+ readonly oxlintConfig?: string;
187
+ /** The npm version the root's `packageManager` field declares, when it names npm. */
188
+ readonly packageManagerNpm?: string;
193
189
  }
194
190
 
195
191
  /**
@@ -339,7 +335,7 @@ export function findBaseTsconfig(
339
335
  }
340
336
 
341
337
  /**
342
- * The repo's prettier `printWidth`, so the emitted sources wrap where the repo
338
+ * The repo's formatter `printWidth`, so the emitted sources wrap where the repo
343
339
  * wraps instead of at the scaffold's own default.
344
340
  *
345
341
  * **Why this is worth detecting at all.** There is no width that is stable for
@@ -360,19 +356,21 @@ export function findBaseTsconfig(
360
356
  * adopter's formatter rewraps on first commit. So a heuristic that is usually
361
357
  * right strictly improves on no detection, and can break nothing.
362
358
  */
363
- export function findPrettierPrintWidth(rootDir: string, probe: WorkspaceProbe): number | undefined {
359
+ export function findFormatterPrintWidth(rootDir: string, probe: WorkspaceProbe): number | undefined {
364
360
  const manifest = probe.readJson(path.join(rootDir, 'package.json'));
365
361
  if (isJsonObject(manifest) && isJsonObject(manifest.prettier) && typeof manifest.prettier.printWidth === 'number') {
366
362
  return manifest.prettier.printWidth;
367
363
  }
368
364
  const present = probe.listFiles(rootDir);
369
- for (const file of present.filter(name => name === '.prettierrc' || name === '.prettierrc.json')) {
365
+ for (const file of present.filter(name => name === '.oxfmtrc.json' || name === '.prettierrc' || name === '.prettierrc.json')) {
370
366
  const parsed = probe.readJson(path.join(rootDir, file));
371
367
  if (isJsonObject(parsed) && typeof parsed.printWidth === 'number') {
372
368
  return parsed.printWidth;
373
369
  }
374
370
  }
375
- for (const file of present.filter(name => /^(\.prettierrc\.[cm]?[jt]s|prettier\.config\.[cm]?[jt]s)$/.test(name))) {
371
+ for (const file of present.filter(name =>
372
+ /^(\.prettierrc\.[cm]?[jt]s|prettier\.config\.[cm]?[jt]s|oxfmt\.config\.[cm]?[jt]s)$/.test(name)
373
+ )) {
376
374
  const width = /\bprintWidth\s*:\s*(\d+)/.exec(probe.readText(path.join(rootDir, file)) ?? '');
377
375
  if (width) {
378
376
  return Number(width[1]);
@@ -398,6 +396,22 @@ export function findEslintConfig(rootDir: string, probe: WorkspaceProbe): string
398
396
  return probe.listFiles(rootDir).find(name => /^eslint\.config\.[cm]?[jt]s$/.test(name) || /^\.eslintrc(\..+)?$/.test(name));
399
397
  }
400
398
 
399
+ /** Detect Oxlint without evaluating executable configuration files. */
400
+ export function findOxlintConfig(rootDir: string, probe: WorkspaceProbe): string | undefined {
401
+ return probe.listFiles(rootDir).find(name => /^(oxlint\.config\.[cm]?[jt]s|\.oxlintrc\.jsonc?)$/.test(name));
402
+ }
403
+
404
+ /** The npm version the root's `packageManager` field declares (`npm@11.15.0` gives `11.15.0`), when it names npm. */
405
+ export function findPackageManagerNpm(rootDir: string, probe: WorkspaceProbe): string | undefined {
406
+ const manifest = probe.readJson(path.join(rootDir, 'package.json'));
407
+ return parseNpmVersion(isJsonObject(manifest) && typeof manifest.packageManager === 'string' ? manifest.packageManager : undefined);
408
+ }
409
+
410
+ /** The npm version, prerelease included, of a `packageManager` field (`npm@…`) or a user agent (`npm/…`); undefined for another tool. */
411
+ export function parseNpmVersion(spec: string | undefined): string | undefined {
412
+ return /^npm[@/](\d+\.\d+\.\d+(?:-[\w.]+)?)/.exec(spec ?? '')?.[1];
413
+ }
414
+
401
415
  /** POSIX-style relative path, which is what both `extends` and `--prefix` want on every platform. */
402
416
  function posixRelative(from: string, to: string): string {
403
417
  return path.relative(from, to).split(path.sep).join('/');
@@ -432,11 +446,12 @@ export function detectWorkspace(targetDir: string, probe: WorkspaceProbe): Works
432
446
  rootDir,
433
447
  workspaces,
434
448
  targetPath,
435
- coveredBy: workspaces.find(glob => workspaceGlobCovers(glob, targetPath)),
436
449
  scope: inferPackageScope(rootDir, workspaces, probe),
437
450
  baseTsconfig: base && posixRelative(absoluteTarget, path.join(rootDir, base.file)),
438
451
  baseCompilerOptions: base?.compilerOptions,
439
- printWidth: findPrettierPrintWidth(rootDir, probe),
440
- eslintConfig: findEslintConfig(rootDir, probe)
452
+ printWidth: findFormatterPrintWidth(rootDir, probe),
453
+ eslintConfig: findEslintConfig(rootDir, probe),
454
+ oxlintConfig: findOxlintConfig(rootDir, probe),
455
+ packageManagerNpm: findPackageManagerNpm(rootDir, probe)
441
456
  };
442
457
  }