@akanjs/cli 3.0.0-alpha.9 → 3.0.0-alpha.90

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 (135) hide show
  1. package/.build-stamp +1 -1
  2. package/README.ko.md +1 -1
  3. package/README.md +1 -1
  4. package/{abstractCompactor-e5yq60qz.js → abstractCompactor-cefxzggj.js} +3 -5
  5. package/{agent.command-f0gqkfgz.js → agent.command-r93wmq7m.js} +11 -13
  6. package/{application.command-x903m2qq.js → application.command-5nqfqgdn.js} +62 -38
  7. package/{applicationBuildRunner-ha3y8ew8.js → applicationBuildRunner-b21m07fs.js} +23 -20
  8. package/{applicationReleasePackager-gg8ccbeh.js → applicationReleasePackager-3wh58n2m.js} +8 -9
  9. package/buildBatch.proc.js +12 -14
  10. package/capacitorApp-gzcx6txb.js +12 -0
  11. package/{cloud.command-zs6kyf83.js → cloud.command-g0pk0k60.js} +15 -18
  12. package/commandManifest.json +1 -1
  13. package/{context.command-fmepgjzg.js → context.command-qd8kqrnh.js} +19 -23
  14. package/dependencyScanner-shs82ynp.js +8 -0
  15. package/devTui-2xf0meaq.js +552 -0
  16. package/devTuiView-7jy8f30g.js +9 -0
  17. package/getDirname-dr3jz1xg.js +7 -0
  18. package/{guideline.command-n6sw0a0c.js → guideline.command-f38x8jhw.js} +16 -18
  19. package/guidelines/agentRule/agentRule.generate.json +31 -0
  20. package/guidelines/agentRule/agentRule.instruction.md +533 -0
  21. package/guidelines/conventions/conventions.instruction.md +406 -197
  22. package/guidelines/cssRule/cssRule.instruction.md +7 -0
  23. package/guidelines/framework/framework.generate.json +3 -2
  24. package/guidelines/framework/framework.instruction.md +1 -9
  25. package/guidelines/mcpRule/mcpRule.generate.json +25 -0
  26. package/guidelines/mcpRule/mcpRule.instruction.md +217 -0
  27. package/guidelines/modelStore/modelStore.instruction.md +12 -0
  28. package/guidelines/modelTemplate/modelTemplate.instruction.md +5 -0
  29. package/guidelines/queryRule/queryRule.generate.json +31 -0
  30. package/guidelines/queryRule/queryRule.instruction.md +143 -0
  31. package/guidelines/runtimeRule/runtimeRule.generate.json +25 -0
  32. package/guidelines/runtimeRule/runtimeRule.instruction.md +213 -0
  33. package/guidelines/ssrRule/ssrRule.instruction.md +49 -5
  34. package/guidelines/transportRule/transportRule.generate.json +31 -0
  35. package/guidelines/transportRule/transportRule.instruction.md +60 -0
  36. package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +51 -760
  37. package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +33 -0
  38. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +402 -0
  39. package/incrementalBuilder.proc.js +26 -25
  40. package/{index-774gcx29.js → index-0emb9eat.js} +41 -34
  41. package/index-3d9y066c.js +76 -0
  42. package/{index-3vta1tqa.js → index-3vvbv974.js} +32 -32
  43. package/{index-76rn3g2c.js → index-47pj3aee.js} +4 -4
  44. package/{index-y4vkyhvv.js → index-5xdqxbn9.js} +14 -14
  45. package/{index-1577bej2.js → index-6wwzs1bc.js} +2 -2
  46. package/{index-wnp7hwq7.js → index-92zztqy1.js} +7 -7
  47. package/{index-jhpa13zj.js → index-9bwhxrqf.js} +57 -57
  48. package/{index-bjpxzr6s.js → index-9wtbw98m.js} +6 -3
  49. package/{index-fgc8r6dj.js → index-a5vmm6x4.js} +3 -1
  50. package/{index-xys926f2.js → index-by5gpp8x.js} +4 -4
  51. package/{index-kdh76j26.js → index-cezy7yb3.js} +100 -32
  52. package/{index-62955kn5.js → index-d61rcfa2.js} +758 -127
  53. package/{index-82jrh4hj.js → index-deekbtkj.js} +13 -13
  54. package/{index-rxkpk7n4.js → index-e82dyeqy.js} +4 -4
  55. package/{index-qzdjd4ct.js → index-h759vjfa.js} +18 -18
  56. package/{index-j37qq1f2.js → index-h7yw2z9n.js} +7 -7
  57. package/{index-qb61h0k7.js → index-jydtyzva.js} +1098 -1360
  58. package/{index-46tjzh6s.js → index-kcxmv48c.js} +29 -29
  59. package/{index-4m0bphac.js → index-kfnr6c19.js} +31 -30
  60. package/{index-xmmzf150.js → index-mpmyqm1y.js} +1 -1
  61. package/{index-xjd3rqzj.js → index-n68jx79w.js} +6 -15
  62. package/{index-0cj2zxbm.js → index-n85fer99.js} +12 -11
  63. package/{index-779ske1y.js → index-pgsswppj.js} +27 -27
  64. package/index-pvb4vdwr.js +159 -0
  65. package/{index-67546d0j.js → index-q0y2jq9j.js} +14 -2
  66. package/{index-z8ptfkzv.js → index-q8sn827n.js} +969 -240
  67. package/{index-5sn5w2mt.js → index-r50qen0z.js} +94 -61
  68. package/{index-eyyf2149.js → index-rntcdss1.js} +36 -37
  69. package/{index-gcv8ncfh.js → index-sjak5v5b.js} +16 -12
  70. package/{index-j9cxndc0.js → index-w8kmx1b6.js} +20 -11
  71. package/{index-jf2ya7r2.js → index-y74k5anj.js} +8 -8
  72. package/{index-d43t8af2.js → index-zkvpaggp.js} +58 -25
  73. package/index.js +22 -25
  74. package/{library.command-cv9gdbmg.js → library.command-em103wtn.js} +11 -10
  75. package/{localRegistry.command-d8fg36zc.js → localRegistry.command-gz8apn4y.js} +20 -23
  76. package/{module.command-qyr1s9cn.js → module.command-451pztkc.js} +13 -16
  77. package/{package.command-wsjx0k47.js → package.command-rfhyf38t.js} +8 -10
  78. package/package.json +5 -7
  79. package/{page.command-rdzg65rm.js → page.command-kt19da5g.js} +7 -9
  80. package/{primitive.command-89g38b53.js → primitive.command-pgy69ere.js} +13 -16
  81. package/{quality.command-0cs2z92d.js → quality.command-gpe2vqb5.js} +226 -105
  82. package/recipeScanner-fpagtgc1.js +11 -0
  83. package/{repair.command-6fphxfwj.js → repair.command-2sbrz187.js} +12 -14
  84. package/{routeSourceValidator-e4jmbfcx.js → routeSourceValidator-ze6x894c.js} +0 -2
  85. package/{scalar.command-xfer69s6.js → scalar.command-jcf4e5sv.js} +11 -14
  86. package/subspace.command-kqzqtk0p.js +755 -0
  87. package/templates/app/env/env.client.debug.ts.template +1 -5
  88. package/templates/app/env/env.client.develop.ts.template +1 -5
  89. package/templates/app/env/env.client.local.ts.template +1 -5
  90. package/templates/app/env/env.client.main.ts.template +1 -5
  91. package/templates/app/env/env.client.testing.ts.template +1 -5
  92. package/templates/app/env/env.client.type.ts +2 -6
  93. package/templates/app/env/env.server.debug.ts.template +1 -5
  94. package/templates/app/env/env.server.develop.ts.template +1 -5
  95. package/templates/app/env/env.server.local.ts.template +1 -5
  96. package/templates/app/env/env.server.main.ts.template +1 -5
  97. package/templates/app/main.ts +3 -1
  98. package/templates/appSample/lib/task/task.signal.ts +11 -6
  99. package/templates/appSample/srvkit/AuthGuard.ts +9 -5
  100. package/templates/appSample/srvkit/SessionInternalArg.ts +4 -3
  101. package/templates/crudPages/[__model__Id]/edit/page.tsx +5 -5
  102. package/templates/crudPages/[__model__Id]/page.tsx +10 -13
  103. package/templates/crudPages/new/page.tsx +5 -5
  104. package/templates/crudPages/page.tsx +9 -9
  105. package/templates/crudSinglePage/page.tsx +11 -7
  106. package/templates/env/_env.server.type.ts +7 -5
  107. package/templates/lib/db.ts +1 -1
  108. package/templates/lib/dict.ts +1 -1
  109. package/templates/lib/sig.ts +1 -1
  110. package/templates/lib/srv.ts +6 -2
  111. package/templates/module/__model__.dictionary.ts +4 -1
  112. package/templates/module/__model__.signal.ts +2 -3
  113. package/templates/module/__model__.store.ts +1 -2
  114. package/templates/workspaceRoot/.gitignore.template +0 -1
  115. package/templates/workspaceRoot/.husky/pre-commit.template +16 -0
  116. package/templates/workspaceRoot/.vscode/settings.json.template +1 -1
  117. package/templates/workspaceRoot/AGENTS.md.template +4 -0
  118. package/templates/workspaceRoot/CLAUDE.md.template +19 -0
  119. package/templates/workspaceRoot/biome.json.template +2 -1
  120. package/templates/workspaceRoot/docs/AI-DEVELOPMENT.md.template +10 -14
  121. package/templates/workspaceRoot/docs/GENERATED.md.template +12 -10
  122. package/templates/workspaceRoot/package.json.template +2 -4
  123. package/typeChecker-3xgrzc2v.js +7 -0
  124. package/typecheck.proc.js +4 -5
  125. package/{workflow.command-2ygfqt4f.js → workflow.command-m4z25a2p.js} +22 -25
  126. package/{workspace.command-88m0zs64.js → workspace.command-dqgj9zbk.js} +96 -81
  127. package/capacitorApp-9xswcgx7.js +0 -61
  128. package/dependencyScanner-f6grrep3.js +0 -9
  129. package/getDirname-m9s0cmhq.js +0 -8
  130. package/index-mxvakhsm.js +0 -66
  131. package/index-r24hmh0q.js +0 -4
  132. package/recipeScanner-tghkzrrt.js +0 -12
  133. package/typeChecker-kravn7ns.js +0 -8
  134. /package/{index-0wae5ebk.js → index-meh558jy.js} +0 -0
  135. /package/{index-ss469dec.js → index-nz8prx9g.js} +0 -0
@@ -1,21 +1,20 @@
1
1
  // @bun
2
- import {
3
- AbstractDoc
4
- } from "./index-0wae5ebk.js";
5
2
  import {
6
3
  Workspace,
7
- command,
8
4
  runner,
9
- script
10
- } from "./index-kdh76j26.js";
5
+ script,
6
+ command
7
+ } from "./index-cezy7yb3.js";
8
+ import"./index-q0y2jq9j.js";
9
+ import {
10
+ rootAllowedFiles,
11
+ rootAllowedDirs,
12
+ isAllowedLibFacetRootFile
13
+ } from "./index-q8sn827n.js";
14
+ import"./index-6wwzs1bc.js";
11
15
  import {
12
- appRootAllowedFiles,
13
- libFacetRootAllowedFiles
14
- } from "./index-z8ptfkzv.js";
15
- import"./index-mxvakhsm.js";
16
- import"./index-1577bej2.js";
17
- import"./index-67546d0j.js";
18
- import"./index-r24hmh0q.js";
16
+ AbstractDoc
17
+ } from "./index-meh558jy.js";
19
18
 
20
19
  // pkgs/@akanjs/devkit/qualityScanner.ts
21
20
  import { createHash } from "crypto";
@@ -23,10 +22,79 @@ import { readdir, readFile, stat } from "fs/promises";
23
22
  import path from "path";
24
23
  import { RESERVED_ROUTE_CONFIG_EXPORTS } from "akanjs/common";
25
24
  import ignore from "ignore";
26
- import ts2 from "typescript";
25
+ import ts3 from "typescript";
27
26
 
28
- // pkgs/@akanjs/devkit/ssrScanner.ts
27
+ // pkgs/@akanjs/devkit/formSetterScanner.ts
29
28
  import ts from "typescript";
29
+
30
+ class FormSetterScanner {
31
+ static #fieldSetter = /^set[A-Za-z0-9_$]*On[A-Za-z0-9_$]*$/;
32
+ scan(sourceFiles) {
33
+ return sourceFiles.filter((sourceFile) => sourceFile.file.endsWith(".tsx")).flatMap((f) => this.#scanFile(f));
34
+ }
35
+ #scanFile({ file, sourceFile }) {
36
+ const wrapped = [];
37
+ const visit = (node) => {
38
+ if (ts.isJsxAttribute(node)) {
39
+ const setter = FormSetterScanner.#wrappedSetterOf(node);
40
+ if (setter)
41
+ wrapped.push({ setter, line: FormSetterScanner.#lineOf(sourceFile, node) });
42
+ }
43
+ ts.forEachChild(node, visit);
44
+ };
45
+ visit(sourceFile);
46
+ if (!wrapped.length)
47
+ return [];
48
+ const setters = [...new Set(wrapped.map((entry) => entry.setter))].sort();
49
+ return [
50
+ {
51
+ rule: "akan.agent.unpublished-form-setter",
52
+ scope: "agent",
53
+ severity: "warning",
54
+ message: setters.length === 1 ? `${setters[0]} is reached through a wrapper, so that field publishes no agent tool and carries no data-akan-action.` : `${setters.length} field setters are reached through a wrapper, so those fields publish no agent tool and carry no data-akan-action: ${setters.join(", ")}.`,
55
+ file,
56
+ line: wrapped[0]?.line,
57
+ locations: wrapped.map(({ line }) => ({ file, line }))
58
+ }
59
+ ];
60
+ }
61
+ static #wrappedSetterOf(attribute) {
62
+ if (!ts.isIdentifier(attribute.name) || !/^on[A-Z]/.test(attribute.name.text))
63
+ return null;
64
+ const initializer = attribute.initializer;
65
+ if (!initializer || !ts.isJsxExpression(initializer) || !initializer.expression)
66
+ return null;
67
+ const handler = initializer.expression;
68
+ if (!ts.isArrowFunction(handler) && !ts.isFunctionExpression(handler))
69
+ return null;
70
+ if (!handler.parameters.length)
71
+ return null;
72
+ return FormSetterScanner.#setterCallIn(handler.body);
73
+ }
74
+ static #setterCallIn(node) {
75
+ let found = null;
76
+ const visit = (current) => {
77
+ if (found)
78
+ return;
79
+ if (ts.isCallExpression(current) && ts.isPropertyAccessExpression(current.expression)) {
80
+ const { expression, name } = current.expression;
81
+ if (ts.isPropertyAccessExpression(expression) && ts.isIdentifier(expression.expression) && expression.expression.text === "st" && expression.name.text === "do" && FormSetterScanner.#fieldSetter.test(name.text)) {
82
+ found = name.text;
83
+ return;
84
+ }
85
+ }
86
+ ts.forEachChild(current, visit);
87
+ };
88
+ visit(node);
89
+ return found;
90
+ }
91
+ static #lineOf(sourceFile, node) {
92
+ return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;
93
+ }
94
+ }
95
+
96
+ // pkgs/@akanjs/devkit/ssrScanner.ts
97
+ import ts2 from "typescript";
30
98
  var STATIC_COMPONENT_MIN_MASS = 4;
31
99
  var MIXED_COMPONENT_MIN_MASS = 10;
32
100
  var MIXED_COMPONENT_MAX_TOUCHES = 2;
@@ -144,31 +212,31 @@ class SsrScanner {
144
212
  });
145
213
  }
146
214
  }
147
- ts.forEachChild(node, visit);
215
+ ts2.forEachChild(node, visit);
148
216
  };
149
- ts.forEachChild(sourceFile.sourceFile, visit);
217
+ ts2.forEachChild(sourceFile.sourceFile, visit);
150
218
  return warnings;
151
219
  }
152
220
  #isMountEffect(sourceFile, node) {
153
- if (!ts.isCallExpression(node))
221
+ if (!ts2.isCallExpression(node))
154
222
  return false;
155
223
  const callee = node.expression.getText(sourceFile);
156
224
  if (callee !== "useEffect" && callee !== "useLayoutEffect")
157
225
  return false;
158
226
  const deps = node.arguments[1];
159
- return !!deps && ts.isArrayLiteralExpression(deps) && deps.elements.length === 0;
227
+ return !!deps && ts2.isArrayLiteralExpression(deps) && deps.elements.length === 0;
160
228
  }
161
229
  #getLoadCalls(sourceFile, node) {
162
230
  const calls = [];
163
231
  const visit = (child) => {
164
- if (ts.isCallExpression(child)) {
232
+ if (ts2.isCallExpression(child)) {
165
233
  const callee = child.expression.getText(sourceFile);
166
234
  if (/^fetch\.[a-z]/.test(callee) || /^st\.do\.(init|get|view|load|list|count|insight)[A-Z]/.test(callee))
167
235
  calls.push({ callee, node: child });
168
236
  }
169
- ts.forEachChild(child, visit);
237
+ ts2.forEachChild(child, visit);
170
238
  };
171
- ts.forEachChild(node, visit);
239
+ ts2.forEachChild(node, visit);
172
240
  return calls;
173
241
  }
174
242
  #getTemplateStateWarnings(sourceFile) {
@@ -176,7 +244,7 @@ class SsrScanner {
176
244
  return [];
177
245
  const warnings = [];
178
246
  const visit = (node) => {
179
- if (ts.isCallExpression(node) && node.expression.getText(sourceFile.sourceFile) === "useState") {
247
+ if (ts2.isCallExpression(node) && node.expression.getText(sourceFile.sourceFile) === "useState") {
180
248
  warnings.push({
181
249
  rule: "akan.ssr.template-client-state",
182
250
  scope: "ssr",
@@ -186,9 +254,9 @@ class SsrScanner {
186
254
  message: "Template holds form state in useState. Templates are store-driven and carry no local state."
187
255
  });
188
256
  }
189
- ts.forEachChild(node, visit);
257
+ ts2.forEachChild(node, visit);
190
258
  };
191
- ts.forEachChild(sourceFile.sourceFile, visit);
259
+ ts2.forEachChild(sourceFile.sourceFile, visit);
192
260
  return warnings;
193
261
  }
194
262
  #measureBalance(sourceFiles) {
@@ -229,14 +297,14 @@ class SsrScanner {
229
297
  return components;
230
298
  }
231
299
  #getComponentNodes(statement) {
232
- if (ts.isFunctionDeclaration(statement) && statement.body)
300
+ if (ts2.isFunctionDeclaration(statement) && statement.body)
233
301
  return [{ name: statement.name?.text ?? "default", node: statement.body }];
234
- if (!ts.isVariableStatement(statement))
302
+ if (!ts2.isVariableStatement(statement))
235
303
  return [];
236
304
  return statement.declarationList.declarations.flatMap((declaration) => {
237
- if (!ts.isIdentifier(declaration.name) || !declaration.initializer)
305
+ if (!ts2.isIdentifier(declaration.name) || !declaration.initializer)
238
306
  return [];
239
- if (!ts.isArrowFunction(declaration.initializer) && !ts.isFunctionExpression(declaration.initializer))
307
+ if (!ts2.isArrowFunction(declaration.initializer) && !ts2.isFunctionExpression(declaration.initializer))
240
308
  return [];
241
309
  return [{ name: declaration.name.text, node: declaration.initializer }];
242
310
  });
@@ -244,7 +312,7 @@ class SsrScanner {
244
312
  #getTouches(sourceFile, node) {
245
313
  const touches = [];
246
314
  const visit = (child) => {
247
- if (ts.isCallExpression(child)) {
315
+ if (ts2.isCallExpression(child)) {
248
316
  const callee = child.expression.getText(sourceFile);
249
317
  const bareName = callee.split(".").pop() ?? callee;
250
318
  if (callee === "createContext" || callee === "lazy")
@@ -252,60 +320,60 @@ class SsrScanner {
252
320
  else if (/^use[A-Z]/.test(bareName) && !SsrScanner.#serverSafeCalls.has(bareName))
253
321
  touches.push(bareName);
254
322
  }
255
- if (ts.isJsxAttribute(child) && /^on[A-Z]/.test(child.name.getText(sourceFile)))
323
+ if (ts2.isJsxAttribute(child) && /^on[A-Z]/.test(child.name.getText(sourceFile)))
256
324
  touches.push(child.name.getText(sourceFile));
257
- if (ts.isPropertyAccessExpression(child)) {
325
+ if (ts2.isPropertyAccessExpression(child)) {
258
326
  const root = getAccessRoot(child);
259
327
  if (root === "st")
260
328
  touches.push("st");
261
329
  else if (SsrScanner.#clientGlobals.has(root))
262
330
  touches.push(root);
263
331
  }
264
- ts.forEachChild(child, visit);
332
+ ts2.forEachChild(child, visit);
265
333
  };
266
- ts.forEachChild(node, visit);
334
+ ts2.forEachChild(node, visit);
267
335
  return touches;
268
336
  }
269
337
  #getTagNames(sourceFile, node) {
270
338
  const tags = new Set;
271
339
  const visit = (child) => {
272
- if (ts.isJsxOpeningElement(child) || ts.isJsxSelfClosingElement(child))
340
+ if (ts2.isJsxOpeningElement(child) || ts2.isJsxSelfClosingElement(child))
273
341
  tags.add(child.tagName.getText(sourceFile).split(".")[0]);
274
- ts.forEachChild(child, visit);
342
+ ts2.forEachChild(child, visit);
275
343
  };
276
- ts.forEachChild(node, visit);
344
+ ts2.forEachChild(node, visit);
277
345
  return tags;
278
346
  }
279
347
  #getMass(node) {
280
348
  let mass = 0;
281
349
  const visit = (child) => {
282
- if (ts.isJsxOpeningElement(child) || ts.isJsxSelfClosingElement(child))
350
+ if (ts2.isJsxOpeningElement(child) || ts2.isJsxSelfClosingElement(child))
283
351
  mass += 1;
284
- ts.forEachChild(child, visit);
352
+ ts2.forEachChild(child, visit);
285
353
  };
286
- ts.forEachChild(node, visit);
354
+ ts2.forEachChild(node, visit);
287
355
  return mass;
288
356
  }
289
357
  #hasUseClient(sourceFile) {
290
358
  const first = sourceFile.statements[0];
291
- if (!first || !ts.isExpressionStatement(first) || !ts.isStringLiteral(first.expression))
359
+ if (!first || !ts2.isExpressionStatement(first) || !ts2.isStringLiteral(first.expression))
292
360
  return false;
293
361
  return first.expression.text === "use client";
294
362
  }
295
363
  #hasVendorImport(sourceFile) {
296
- return sourceFile.statements.some((statement) => ts.isImportDeclaration(statement) && isVendorSpecifier(getSpecifier(statement)));
364
+ return sourceFile.statements.some((statement) => ts2.isImportDeclaration(statement) && isVendorSpecifier(getSpecifier(statement)));
297
365
  }
298
366
  #getVendorNames(sourceFile) {
299
367
  const names = new Set;
300
368
  for (const statement of sourceFile.statements) {
301
- if (!ts.isImportDeclaration(statement) || !isVendorSpecifier(getSpecifier(statement)))
369
+ if (!ts2.isImportDeclaration(statement) || !isVendorSpecifier(getSpecifier(statement)))
302
370
  continue;
303
371
  const clause = statement.importClause;
304
372
  if (clause?.name)
305
373
  names.add(clause.name.text);
306
- if (clause?.namedBindings && ts.isNamespaceImport(clause.namedBindings))
374
+ if (clause?.namedBindings && ts2.isNamespaceImport(clause.namedBindings))
307
375
  names.add(clause.namedBindings.name.text);
308
- if (clause?.namedBindings && ts.isNamedImports(clause.namedBindings))
376
+ if (clause?.namedBindings && ts2.isNamedImports(clause.namedBindings))
309
377
  for (const element of clause.namedBindings.elements)
310
378
  names.add(element.name.text);
311
379
  }
@@ -313,10 +381,10 @@ class SsrScanner {
313
381
  }
314
382
  #importsClientRuntime(sourceFile) {
315
383
  for (const statement of sourceFile.statements) {
316
- if (!ts.isImportDeclaration(statement))
384
+ if (!ts2.isImportDeclaration(statement))
317
385
  continue;
318
386
  const bindings = statement.importClause?.namedBindings;
319
- if (!bindings || !ts.isNamedImports(bindings))
387
+ if (!bindings || !ts2.isNamedImports(bindings))
320
388
  continue;
321
389
  if (bindings.elements.some((element) => SsrScanner.#clientRuntimeImports.has(element.name.text)))
322
390
  return true;
@@ -367,7 +435,7 @@ function getShare(serverMass, clientMass) {
367
435
  return total === 0 ? 1 : serverMass / total;
368
436
  }
369
437
  function getSpecifier(statement) {
370
- return ts.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : "";
438
+ return ts2.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : "";
371
439
  }
372
440
  function isVendorSpecifier(specifier) {
373
441
  if (specifier === "" || specifier.startsWith(".") || specifier.startsWith("/"))
@@ -380,9 +448,9 @@ function isVendorSpecifier(specifier) {
380
448
  }
381
449
  function getAccessRoot(node) {
382
450
  let current = node;
383
- while (ts.isPropertyAccessExpression(current))
451
+ while (ts2.isPropertyAccessExpression(current))
384
452
  current = current.expression;
385
- return ts.isIdentifier(current) ? current.text : "";
453
+ return ts2.isIdentifier(current) ? current.text : "";
386
454
  }
387
455
 
388
456
  // pkgs/@akanjs/devkit/qualityScanner.ts
@@ -406,7 +474,8 @@ var SUGGESTED_RULES = [
406
474
  "Keep apps/*/lib and libs/*/lib root files limited to generated support facets such as cnst.ts, db.ts, dict.ts, sig.ts, srv.ts, st.ts, useClient.ts, and useServer.ts.",
407
475
  "Use domain module folders consistently: lib/<model> for database modules, lib/_<service> for service modules, and lib/__scalar/<scalar> for scalar modules.",
408
476
  "Keep module UI filenames predictable: database modules use <Model>.Template/Unit/Util/View/Zone.tsx, service modules use <Service>.Util/Zone.tsx, and scalar modules use <Scalar>.Template/Unit.tsx.",
409
- "Move shared app utilities to apps/*/common instead of creating apps/*/base.",
477
+ "Hand a form control its store setter by reference so the field publishes an agent tool; put normalization in the control's transform prop and a multi-write in a _postSet<Field> hook on the store.",
478
+ "Move shared app and lib utilities to common/ instead of creating apps/*/base or libs/*/base.",
410
479
  "Avoid large mixed-purpose class files; class export files should import helpers from neighboring utility files instead of declaring them inline."
411
480
  ];
412
481
  var CONVENTION_SUFFIXES = [
@@ -424,15 +493,20 @@ var RULE_FIXES = {
424
493
  "akan.file.max-lines": "Break the file into smaller focused modules; keep one primary responsibility per file.",
425
494
  "akan.file.abstract-max-lines": "Run `akan compact <app-or-lib>` to rewrite the abstract with the AI editor, keeping only the invariants and workflows the source files cannot show.",
426
495
  "akan.file.placeholder-export": "Remove the placeholder export; generated indexes should only re-export real modules.",
496
+ "akan.file.bang-comment-in-client": "Rewrite the marker as `// FIXME:` or `// TODO:`. Keep the bang form for server, srvkit, and CLI files.",
427
497
  "akan.file.dictionary-stale-text": "Replace the scaffold text with real localized copy for this dictionary entry.",
428
498
  "akan.file.global-declaration": "Move the global declaration into an approved low-level integration file (e.g. webkit) and keep it isolated.",
429
499
  "akan.file.window-augmentation": "Move the Window augmentation into an approved browser integration file and keep it isolated.",
430
500
  "akan.file.prototype-mutation": "Avoid prototype mutation, or isolate it in an approved low-level integration file.",
431
501
  "akan.file.class-export-global-declaration": "Move the helper to a sibling file and import it into the class module.",
502
+ "akan.agent.unpublished-form-setter": "Pass the setter by reference where the wrapper only forwards (onChange={st.do.setTitleOnTask}); move normalization into the control's own transform prop; move a multi-write into a _postSet<Field> hook on the store, keeping the generated setter on the control.",
432
503
  "akan.file.component-internal-declaration": "Move the type or helper to a type/util file in ui/, webkit/, or common/ by purpose. If it is the component's props, declare it as `interface <Component>Props`.",
433
504
  "akan.file.component-export": "Move the value or type to a util/constant/type file in ui/, webkit/, or common/ and import it. Adding `export` is not a valid fix \u2014 only PascalCase components and their `<Component>Props` interface belong here.",
434
505
  "akan.layout.app-root-file": "Move the file into a conventional app folder (common, env, lib, page, private, public, script, srvkit, ui, or webkit).",
435
- "akan.layout.lib-root-file": "Move the file into a domain module folder under lib/; keep lib root limited to generated support facets.",
506
+ "akan.layout.app-root-folder": "Move the folder's contents into a conventional app folder (common, env, lib, page, private, public, script, srvkit, ui, or webkit) and delete it.",
507
+ "akan.layout.lib-root-file": "Move the file into a conventional lib folder (common, env, lib, page, private, public, srvkit, ui, or webkit).",
508
+ "akan.layout.lib-root-folder": "Move the folder's contents into a conventional lib folder (common, env, lib, page, private, public, srvkit, ui, or webkit) and delete it.",
509
+ "akan.layout.lib-facet-file": "Move the file into a domain module folder under lib/; keep the lib facet root limited to generated support facets.",
436
510
  "akan.layout.module-ui-file": "Rename the file to an allowed module UI name, or move it to ui/ if it is not a module component.",
437
511
  "akan.ssr.unnecessary-use-client": 'Delete the "use client" directive so the file renders on the server. If it exists only to wrap one client child, drop the wrapper and use the child directly.',
438
512
  "akan.ssr.client-static-component": "Move the component to a server file \u2014 a <Model>.Unit.tsx / <Model>.View.tsx for a module, or a ui/ file with no directive \u2014 and reference it from the client file.",
@@ -460,6 +534,7 @@ class AkanQualityScanner {
460
534
  ...sourceFiles.flatMap((sourceFile) => this.#scanConventionQuality(sourceFile)),
461
535
  ...sourceFiles.flatMap((sourceFile) => this.#scanLayoutQuality(sourceFile)),
462
536
  ...abstractFiles.flatMap((abstractFile) => this.#scanAbstractQuality(abstractFile)),
537
+ ...new FormSetterScanner().scan(sourceFiles),
463
538
  ...ssr.warnings
464
539
  ];
465
540
  return {
@@ -512,7 +587,7 @@ class AkanQualityScanner {
512
587
  file,
513
588
  absolutePath,
514
589
  content,
515
- sourceFile: ts2.createSourceFile(file, content, ts2.ScriptTarget.Latest, true, getScriptKind(file))
590
+ sourceFile: ts3.createSourceFile(file, content, ts3.ScriptTarget.Latest, true, getScriptKind(file))
516
591
  };
517
592
  }
518
593
  async#readTextFile(workspaceRoot, file) {
@@ -570,6 +645,7 @@ class AkanQualityScanner {
570
645
  message: `File has ${lineCount} lines. Keep single files under ${MAX_FILE_LINES} lines.`
571
646
  });
572
647
  }
648
+ warnings.push(...getBangCommentWarnings(sourceFile));
573
649
  warnings.push(...getPlaceholderExportWarnings(sourceFile));
574
650
  warnings.push(...getDictionaryTextWarnings(sourceFile));
575
651
  warnings.push(...getGlobalMutationWarnings(sourceFile));
@@ -671,25 +747,30 @@ class AkanQualityScanner {
671
747
  ];
672
748
  }
673
749
  #scanLayoutQuality(sourceFile) {
674
- const segments = sourceFile.file.split("/");
675
750
  const warnings = [];
676
- if (segments[0] === "apps" && segments.length === 3 && !appRootAllowedFiles.has(segments[2])) {
677
- warnings.push({
678
- rule: "akan.layout.app-root-file",
679
- scope: "layout",
680
- severity: "warning",
681
- file: sourceFile.file,
682
- message: `Unexpected app root file "${segments[2]}". Keep application code in conventional app folders.`
683
- });
751
+ const rootEntry = getSysRootEntry(sourceFile.file);
752
+ if (rootEntry) {
753
+ const { type, name, isDir } = rootEntry;
754
+ const allowed = isDir ? rootAllowedDirs[type].has(name) : rootAllowedFiles[type].has(name);
755
+ const kind = isDir ? "folder" : "file";
756
+ if (!allowed) {
757
+ warnings.push({
758
+ rule: `akan.layout.${type}-root-${kind}`,
759
+ scope: "layout",
760
+ severity: "warning",
761
+ file: sourceFile.file,
762
+ message: `Unexpected ${type} root ${kind} "${name}". Keep ${type} code in conventional ${type} folders.`
763
+ });
764
+ }
684
765
  }
685
- const libRootFile = getLibRootFile(sourceFile.file);
686
- if (libRootFile && !libFacetRootAllowedFiles.has(libRootFile)) {
766
+ const libFacetFile = getLibFacetRootFile(sourceFile.file);
767
+ if (libFacetFile && !isAllowedLibFacetRootFile(libFacetFile)) {
687
768
  warnings.push({
688
- rule: "akan.layout.lib-root-file",
769
+ rule: "akan.layout.lib-facet-file",
689
770
  scope: "layout",
690
771
  severity: "warning",
691
772
  file: sourceFile.file,
692
- message: `Unexpected lib root file "${libRootFile}". Keep direct lib root files limited to generated support facets.`
773
+ message: `Unexpected lib facet root file "${libFacetFile}". Keep direct lib/ root files limited to generated support facets.`
693
774
  });
694
775
  }
695
776
  const moduleUiWarning = getModuleUiWarning(sourceFile.file);
@@ -759,7 +840,7 @@ function getExportedFunctionLikes(sourceFile) {
759
840
  const declarations = [];
760
841
  const nameExempt = isPageRouteFile(sourceFile.file) || isUiComponentFile(sourceFile.file);
761
842
  for (const statement of sourceFile.sourceFile.statements) {
762
- if (ts2.isFunctionDeclaration(statement) && statement.name && isExported(statement)) {
843
+ if (ts3.isFunctionDeclaration(statement) && statement.name && isExported(statement)) {
763
844
  declarations.push({
764
845
  name: statement.name.text,
765
846
  kind: "function",
@@ -769,7 +850,7 @@ function getExportedFunctionLikes(sourceFile) {
769
850
  duplicateNameExempt: nameExempt || isConventionDuplicateNameExempt(sourceFile.file, false)
770
851
  });
771
852
  }
772
- if (ts2.isClassDeclaration(statement) && statement.name && isExported(statement)) {
853
+ if (ts3.isClassDeclaration(statement) && statement.name && isExported(statement)) {
773
854
  declarations.push({
774
855
  name: statement.name.text,
775
856
  kind: "class",
@@ -779,9 +860,9 @@ function getExportedFunctionLikes(sourceFile) {
779
860
  duplicateNameExempt: nameExempt || isConventionDuplicateNameExempt(sourceFile.file, isEnumClassStatement(sourceFile.sourceFile, statement))
780
861
  });
781
862
  }
782
- if (ts2.isVariableStatement(statement) && isExported(statement)) {
863
+ if (ts3.isVariableStatement(statement) && isExported(statement)) {
783
864
  for (const declaration of statement.declarationList.declarations) {
784
- if (!ts2.isIdentifier(declaration.name) || !isFunctionLikeInitializer(declaration.initializer))
865
+ if (!ts3.isIdentifier(declaration.name) || !isFunctionLikeInitializer(declaration.initializer))
785
866
  continue;
786
867
  declarations.push({
787
868
  name: declaration.name.text,
@@ -820,14 +901,14 @@ function isInLibModule(file) {
820
901
  return (segments[0] === "apps" || segments[0] === "libs") && segments.includes("lib");
821
902
  }
822
903
  function isEnumClassStatement(sourceFile, statement) {
823
- if (!ts2.isClassDeclaration(statement))
904
+ if (!ts3.isClassDeclaration(statement))
824
905
  return false;
825
- const heritageClause = statement.heritageClauses?.find((clause) => clause.token === ts2.SyntaxKind.ExtendsKeyword);
906
+ const heritageClause = statement.heritageClauses?.find((clause) => clause.token === ts3.SyntaxKind.ExtendsKeyword);
826
907
  const expression = heritageClause?.types[0]?.expression;
827
908
  return !!expression && expression.getText(sourceFile).startsWith("enumOf(");
828
909
  }
829
910
  function getExportedClassNames(sourceFile) {
830
- return sourceFile.statements.filter((statement) => ts2.isClassDeclaration(statement) && !!statement.name).filter((statement) => isExported(statement)).map((statement) => statement.name.text);
911
+ return sourceFile.statements.filter((statement) => ts3.isClassDeclaration(statement)).filter((statement) => isExported(statement)).map((statement) => statement.name?.text).filter((name) => !!name);
831
912
  }
832
913
  function isComponentDeclarationFile(file) {
833
914
  if (!file.endsWith(".tsx"))
@@ -843,7 +924,7 @@ function isComponentDeclarationFile(file) {
843
924
  function getComponentFileDeclarations(sourceFile) {
844
925
  const reExportedNames = new Set;
845
926
  for (const statement of sourceFile.statements) {
846
- if (ts2.isExportDeclaration(statement) && statement.exportClause && ts2.isNamedExports(statement.exportClause)) {
927
+ if (ts3.isExportDeclaration(statement) && statement.exportClause && ts3.isNamedExports(statement.exportClause)) {
847
928
  for (const element of statement.exportClause.elements)
848
929
  reExportedNames.add((element.propertyName ?? element.name).text);
849
930
  }
@@ -853,19 +934,19 @@ function getComponentFileDeclarations(sourceFile) {
853
934
  const isDefaultExport = isDefaultExportStatement(statement);
854
935
  const inlineExported = isExported(statement);
855
936
  const add = (name, kind, line) => declarations.push({ name, kind, line, exported: inlineExported || reExportedNames.has(name), isDefaultExport });
856
- if (ts2.isInterfaceDeclaration(statement))
937
+ if (ts3.isInterfaceDeclaration(statement))
857
938
  add(statement.name.text, "interface", getLine(sourceFile, statement));
858
- else if (ts2.isTypeAliasDeclaration(statement))
939
+ else if (ts3.isTypeAliasDeclaration(statement))
859
940
  add(statement.name.text, "type", getLine(sourceFile, statement));
860
- else if (ts2.isEnumDeclaration(statement))
941
+ else if (ts3.isEnumDeclaration(statement))
861
942
  add(statement.name.text, "enum", getLine(sourceFile, statement));
862
- else if (ts2.isFunctionDeclaration(statement) && statement.name)
943
+ else if (ts3.isFunctionDeclaration(statement) && statement.name)
863
944
  add(statement.name.text, "function", getLine(sourceFile, statement));
864
- else if (ts2.isClassDeclaration(statement) && statement.name)
945
+ else if (ts3.isClassDeclaration(statement) && statement.name)
865
946
  add(statement.name.text, "class", getLine(sourceFile, statement));
866
- else if (ts2.isVariableStatement(statement)) {
947
+ else if (ts3.isVariableStatement(statement)) {
867
948
  for (const declaration of statement.declarationList.declarations) {
868
- if (!ts2.isIdentifier(declaration.name))
949
+ if (!ts3.isIdentifier(declaration.name))
869
950
  continue;
870
951
  const kind = isFunctionLikeInitializer(declaration.initializer) ? "function" : "variable";
871
952
  add(declaration.name.text, kind, getLine(sourceFile, declaration));
@@ -877,15 +958,15 @@ function getComponentFileDeclarations(sourceFile) {
877
958
  function getCompoundComponentNames(sourceFile) {
878
959
  const names = new Set;
879
960
  for (const statement of sourceFile.statements) {
880
- if (!ts2.isExpressionStatement(statement))
961
+ if (!ts3.isExpressionStatement(statement))
881
962
  continue;
882
963
  const { expression } = statement;
883
- if (!ts2.isBinaryExpression(expression) || expression.operatorToken.kind !== ts2.SyntaxKind.EqualsToken)
964
+ if (!ts3.isBinaryExpression(expression) || expression.operatorToken.kind !== ts3.SyntaxKind.EqualsToken)
884
965
  continue;
885
- if (!ts2.isPropertyAccessExpression(expression.left) || !isPascalCaseName(expression.left.name.text))
966
+ if (!ts3.isPropertyAccessExpression(expression.left) || !isPascalCaseName(expression.left.name.text))
886
967
  continue;
887
968
  names.add(expression.left.name.text);
888
- if (ts2.isIdentifier(expression.right) && isPascalCaseName(expression.right.text))
969
+ if (ts3.isIdentifier(expression.right) && isPascalCaseName(expression.right.text))
889
970
  names.add(expression.right.text);
890
971
  }
891
972
  return names;
@@ -905,9 +986,37 @@ function isPascalCaseName(name) {
905
986
  return /^[A-Z]/.test(name) && !/^[A-Z0-9_]+$/.test(name);
906
987
  }
907
988
  function isDefaultExportStatement(statement) {
908
- if (ts2.isExportAssignment(statement))
989
+ if (ts3.isExportAssignment(statement))
909
990
  return !statement.isExportEquals;
910
- return !!(ts2.getCombinedModifierFlags(statement) & ts2.ModifierFlags.Default);
991
+ if (!ts3.canHaveModifiers(statement))
992
+ return false;
993
+ return !!ts3.getModifiers(statement)?.some((modifier) => modifier.kind === ts3.SyntaxKind.DefaultKeyword);
994
+ }
995
+ function getBangCommentWarnings(sourceFile) {
996
+ if (!isClientReachableFile(sourceFile.file))
997
+ return [];
998
+ return findPatternLines(sourceFile.content, /(?:^|[^\s/][ \t]+)\/[*/]!/).map((line) => ({
999
+ rule: "akan.file.bang-comment-in-client",
1000
+ scope: "file",
1001
+ severity: "warning",
1002
+ file: sourceFile.file,
1003
+ line,
1004
+ message: "A `//!` or `/*!` marker survives minification and ships to the browser."
1005
+ }));
1006
+ }
1007
+ function isClientReachableFile(file) {
1008
+ if (/\.(test|spec)\.tsx?$/.test(file))
1009
+ return false;
1010
+ if (/\.(constant|store)\.ts$/.test(file))
1011
+ return true;
1012
+ if (/\.(Template|Unit|Util|View|Zone)\.tsx$/.test(file))
1013
+ return true;
1014
+ const segments = file.split("/");
1015
+ if (segments.includes("ui") || segments.includes("webkit"))
1016
+ return /\.tsx?$/.test(file);
1017
+ if (segments.includes("common"))
1018
+ return file.endsWith(".ts");
1019
+ return segments.includes("page") && file.endsWith(".tsx");
911
1020
  }
912
1021
  function getPlaceholderExportWarnings(sourceFile) {
913
1022
  if (!sourceFile.file.endsWith("/index.ts") && !sourceFile.file.endsWith("/index.tsx"))
@@ -937,7 +1046,7 @@ function getDictionaryTextWarnings(sourceFile) {
937
1046
  function getGlobalMutationWarnings(sourceFile) {
938
1047
  const warnings = [];
939
1048
  for (const statement of sourceFile.sourceFile.statements) {
940
- if (ts2.isModuleDeclaration(statement) && statement.name.getText(sourceFile.sourceFile) === "global") {
1049
+ if (ts3.isModuleDeclaration(statement) && statement.name.getText(sourceFile.sourceFile) === "global") {
941
1050
  warnings.push({
942
1051
  rule: "akan.file.global-declaration",
943
1052
  scope: "file",
@@ -947,7 +1056,7 @@ function getGlobalMutationWarnings(sourceFile) {
947
1056
  message: "Global declarations require an explicit low-level integration allowlist."
948
1057
  });
949
1058
  }
950
- if (ts2.isInterfaceDeclaration(statement) && statement.name.text === "Window") {
1059
+ if (ts3.isInterfaceDeclaration(statement) && statement.name.text === "Window") {
951
1060
  warnings.push({
952
1061
  rule: "akan.file.window-augmentation",
953
1062
  scope: "file",
@@ -957,7 +1066,7 @@ function getGlobalMutationWarnings(sourceFile) {
957
1066
  message: "Window augmentation should be isolated to approved browser integration files."
958
1067
  });
959
1068
  }
960
- if (ts2.isExpressionStatement(statement) && statement.expression.getText(sourceFile.sourceFile).includes(".prototype.")) {
1069
+ if (ts3.isExpressionStatement(statement) && statement.expression.getText(sourceFile.sourceFile).includes(".prototype.")) {
961
1070
  warnings.push({
962
1071
  rule: "akan.file.prototype-mutation",
963
1072
  scope: "file",
@@ -975,23 +1084,23 @@ function getTopLevelDeclarations(sourceFile) {
975
1084
  }
976
1085
  function getTopLevelDeclaration(sourceFile, statement) {
977
1086
  const line = getLine(sourceFile, statement);
978
- if (ts2.isClassDeclaration(statement) && statement.name) {
1087
+ if (ts3.isClassDeclaration(statement) && statement.name) {
979
1088
  return [{ name: statement.name.text, kind: "class", line, exported: isExported(statement), node: statement }];
980
1089
  }
981
- if (ts2.isFunctionDeclaration(statement) && statement.name) {
1090
+ if (ts3.isFunctionDeclaration(statement) && statement.name) {
982
1091
  return [{ name: statement.name.text, kind: "function", line, exported: isExported(statement), node: statement }];
983
1092
  }
984
- if (ts2.isInterfaceDeclaration(statement)) {
1093
+ if (ts3.isInterfaceDeclaration(statement)) {
985
1094
  return [{ name: statement.name.text, kind: "interface", line, exported: isExported(statement), node: statement }];
986
1095
  }
987
- if (ts2.isTypeAliasDeclaration(statement)) {
1096
+ if (ts3.isTypeAliasDeclaration(statement)) {
988
1097
  return [{ name: statement.name.text, kind: "type", line, exported: isExported(statement), node: statement }];
989
1098
  }
990
- if (ts2.isEnumDeclaration(statement)) {
1099
+ if (ts3.isEnumDeclaration(statement)) {
991
1100
  return [{ name: statement.name.text, kind: "enum", line, exported: isExported(statement), node: statement }];
992
1101
  }
993
- if (ts2.isVariableStatement(statement)) {
994
- return statement.declarationList.declarations.filter((declaration) => ts2.isIdentifier(declaration.name)).map((declaration) => ({
1102
+ if (ts3.isVariableStatement(statement)) {
1103
+ return statement.declarationList.declarations.filter((declaration) => ts3.isIdentifier(declaration.name)).map((declaration) => ({
995
1104
  name: declaration.name.text,
996
1105
  kind: "variable",
997
1106
  line: getLine(sourceFile, declaration),
@@ -999,7 +1108,7 @@ function getTopLevelDeclaration(sourceFile, statement) {
999
1108
  node: statement
1000
1109
  }));
1001
1110
  }
1002
- if (ts2.isExportDeclaration(statement)) {
1111
+ if (ts3.isExportDeclaration(statement)) {
1003
1112
  return [{ name: "export declaration", kind: "export", line, exported: true, node: statement }];
1004
1113
  }
1005
1114
  return [];
@@ -1024,9 +1133,9 @@ function isAllowedConstantDeclaration(modelName, declaration) {
1024
1133
  return false;
1025
1134
  if ([`${modelName}Input`, `${modelName}Object`, modelName, `Light${modelName}`, `${modelName}Insight`].includes(declaration.name))
1026
1135
  return true;
1027
- if (!ts2.isClassDeclaration(declaration.node))
1136
+ if (!ts3.isClassDeclaration(declaration.node))
1028
1137
  return false;
1029
- const heritageClause = declaration.node.heritageClauses?.find((clause) => clause.token === ts2.SyntaxKind.ExtendsKeyword);
1138
+ const heritageClause = declaration.node.heritageClauses?.find((clause) => clause.token === ts3.SyntaxKind.ExtendsKeyword);
1030
1139
  const expression = heritageClause?.types[0]?.expression;
1031
1140
  return !!expression && expression.getText().startsWith("enumOf(");
1032
1141
  }
@@ -1043,7 +1152,19 @@ function getConventionDescription(suffix, modelName) {
1043
1152
  return `${modelName}Internal, ${modelName}Slice, or ${modelName}Endpoint`;
1044
1153
  return `${modelName}Store`;
1045
1154
  }
1046
- function getLibRootFile(file) {
1155
+ var sysRootTypes = { apps: "app", libs: "lib" };
1156
+ function getSysRootEntry(file) {
1157
+ const segments = file.split("/");
1158
+ const root = segments[0];
1159
+ const name = segments[2];
1160
+ if (!root || !name || segments.length < 3)
1161
+ return null;
1162
+ const type = sysRootTypes[root];
1163
+ if (!type)
1164
+ return null;
1165
+ return { type, name, isDir: segments.length > 3 };
1166
+ }
1167
+ function getLibFacetRootFile(file) {
1047
1168
  const segments = file.split("/");
1048
1169
  if ((segments[0] === "libs" || segments[0] === "apps") && segments.length === 4 && segments[2] === "lib")
1049
1170
  return segments[3];
@@ -1092,13 +1213,13 @@ function getModuleInfo(file) {
1092
1213
  return { moduleName, fileName, kind: "database" };
1093
1214
  }
1094
1215
  function isExportedConst(declaration) {
1095
- return declaration.exported && ts2.isVariableStatement(declaration.node) && (declaration.node.declarationList.flags & ts2.NodeFlags.Const) !== 0;
1216
+ return declaration.exported && ts3.isVariableStatement(declaration.node) && (declaration.node.declarationList.flags & ts3.NodeFlags.Const) !== 0;
1096
1217
  }
1097
1218
  function isExported(node) {
1098
- return !!ts2.getCombinedModifierFlags(node) && !!(ts2.getCombinedModifierFlags(node) & ts2.ModifierFlags.Export);
1219
+ return !!ts3.getCombinedModifierFlags(node) && !!(ts3.getCombinedModifierFlags(node) & ts3.ModifierFlags.Export);
1099
1220
  }
1100
1221
  function isFunctionLikeInitializer(node) {
1101
- return !!node && (ts2.isArrowFunction(node) || ts2.isFunctionExpression(node));
1222
+ return !!node && (ts3.isArrowFunction(node) || ts3.isFunctionExpression(node));
1102
1223
  }
1103
1224
  function getBodyFingerprint(sourceFile, node) {
1104
1225
  if (!node)
@@ -1120,7 +1241,7 @@ async function isDirectory(absolutePath) {
1120
1241
  }
1121
1242
  }
1122
1243
  function getScriptKind(file) {
1123
- return file.endsWith(".tsx") ? ts2.ScriptKind.TSX : ts2.ScriptKind.TS;
1244
+ return file.endsWith(".tsx") ? ts3.ScriptKind.TSX : ts3.ScriptKind.TS;
1124
1245
  }
1125
1246
  function getLine(sourceFile, node) {
1126
1247
  return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;