@akanjs/cli 3.0.0-alpha.35 → 3.0.0-alpha.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.build-stamp CHANGED
@@ -1 +1 @@
1
- 19d013737b1748d534b589ea7399041a437db6f36d396f7ce0e2617c8883bf31
1
+ 195b252da01339bc871684c59b5d01377d4145d281c8e2f13c92a91f9174f9e0
package/index.js CHANGED
@@ -31,7 +31,7 @@ var commandModules = {
31
31
  guideline: async () => (await import("./guideline.command-s4hn2bsy.js")).GuidelineCommand,
32
32
  scalar: async () => (await import("./scalar.command-rm6k3c65.js")).ScalarCommand,
33
33
  primitive: async () => (await import("./primitive.command-bw0nes6x.js")).PrimitiveCommand,
34
- quality: async () => (await import("./quality.command-f8drhx6c.js")).QualityCommand,
34
+ quality: async () => (await import("./quality.command-3kd7z1mb.js")).QualityCommand,
35
35
  repair: async () => (await import("./repair.command-mzwtejpk.js")).RepairCommand,
36
36
  workflow: async () => (await import("./workflow.command-g2cgcgxn.js")).WorkflowCommand
37
37
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/cli",
3
- "version": "3.0.0-alpha.35",
3
+ "version": "3.0.0-alpha.36",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -34,7 +34,7 @@
34
34
  "@langchain/openai": "^1.4.6",
35
35
  "@tailwindcss/node": "^4.3.0",
36
36
  "@trapezedev/project": "^7.1.4",
37
- "akanjs": "3.0.0-alpha.35",
37
+ "akanjs": "3.0.0-alpha.36",
38
38
  "chalk": "^5.6.2",
39
39
  "commander": "^14.0.3",
40
40
  "dayjs": "^1.11.20",
@@ -23,10 +23,79 @@ import { readdir, readFile, stat } from "fs/promises";
23
23
  import path from "path";
24
24
  import { RESERVED_ROUTE_CONFIG_EXPORTS } from "akanjs/common";
25
25
  import ignore from "ignore";
26
- import ts2 from "typescript";
26
+ import ts3 from "typescript";
27
27
 
28
- // pkgs/@akanjs/devkit/ssrScanner.ts
28
+ // pkgs/@akanjs/devkit/formSetterScanner.ts
29
29
  import ts from "typescript";
30
+
31
+ class FormSetterScanner {
32
+ static #fieldSetter = /^set[A-Za-z0-9_$]*On[A-Za-z0-9_$]*$/;
33
+ scan(sourceFiles) {
34
+ return sourceFiles.filter((sourceFile) => sourceFile.file.endsWith(".tsx")).flatMap((f) => this.#scanFile(f));
35
+ }
36
+ #scanFile({ file, sourceFile }) {
37
+ const wrapped = [];
38
+ const visit = (node) => {
39
+ if (ts.isJsxAttribute(node)) {
40
+ const setter = FormSetterScanner.#wrappedSetterOf(node);
41
+ if (setter)
42
+ wrapped.push({ setter, line: FormSetterScanner.#lineOf(sourceFile, node) });
43
+ }
44
+ ts.forEachChild(node, visit);
45
+ };
46
+ visit(sourceFile);
47
+ if (!wrapped.length)
48
+ return [];
49
+ const setters = [...new Set(wrapped.map((entry) => entry.setter))].sort();
50
+ return [
51
+ {
52
+ rule: "akan.agent.unpublished-form-setter",
53
+ scope: "agent",
54
+ severity: "warning",
55
+ 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(", ")}.`,
56
+ file,
57
+ line: wrapped[0]?.line,
58
+ locations: wrapped.map(({ line }) => ({ file, line }))
59
+ }
60
+ ];
61
+ }
62
+ static #wrappedSetterOf(attribute) {
63
+ if (!ts.isIdentifier(attribute.name) || !/^on[A-Z]/.test(attribute.name.text))
64
+ return null;
65
+ const initializer = attribute.initializer;
66
+ if (!initializer || !ts.isJsxExpression(initializer) || !initializer.expression)
67
+ return null;
68
+ const handler = initializer.expression;
69
+ if (!ts.isArrowFunction(handler) && !ts.isFunctionExpression(handler))
70
+ return null;
71
+ if (!handler.parameters.length)
72
+ return null;
73
+ return FormSetterScanner.#setterCallIn(handler.body);
74
+ }
75
+ static #setterCallIn(node) {
76
+ let found = null;
77
+ const visit = (current) => {
78
+ if (found)
79
+ return;
80
+ if (ts.isCallExpression(current) && ts.isPropertyAccessExpression(current.expression)) {
81
+ const { expression, name } = current.expression;
82
+ if (ts.isPropertyAccessExpression(expression) && ts.isIdentifier(expression.expression) && expression.expression.text === "st" && expression.name.text === "do" && FormSetterScanner.#fieldSetter.test(name.text)) {
83
+ found = name.text;
84
+ return;
85
+ }
86
+ }
87
+ ts.forEachChild(current, visit);
88
+ };
89
+ visit(node);
90
+ return found;
91
+ }
92
+ static #lineOf(sourceFile, node) {
93
+ return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;
94
+ }
95
+ }
96
+
97
+ // pkgs/@akanjs/devkit/ssrScanner.ts
98
+ import ts2 from "typescript";
30
99
  var STATIC_COMPONENT_MIN_MASS = 4;
31
100
  var MIXED_COMPONENT_MIN_MASS = 10;
32
101
  var MIXED_COMPONENT_MAX_TOUCHES = 2;
@@ -144,31 +213,31 @@ class SsrScanner {
144
213
  });
145
214
  }
146
215
  }
147
- ts.forEachChild(node, visit);
216
+ ts2.forEachChild(node, visit);
148
217
  };
149
- ts.forEachChild(sourceFile.sourceFile, visit);
218
+ ts2.forEachChild(sourceFile.sourceFile, visit);
150
219
  return warnings;
151
220
  }
152
221
  #isMountEffect(sourceFile, node) {
153
- if (!ts.isCallExpression(node))
222
+ if (!ts2.isCallExpression(node))
154
223
  return false;
155
224
  const callee = node.expression.getText(sourceFile);
156
225
  if (callee !== "useEffect" && callee !== "useLayoutEffect")
157
226
  return false;
158
227
  const deps = node.arguments[1];
159
- return !!deps && ts.isArrayLiteralExpression(deps) && deps.elements.length === 0;
228
+ return !!deps && ts2.isArrayLiteralExpression(deps) && deps.elements.length === 0;
160
229
  }
161
230
  #getLoadCalls(sourceFile, node) {
162
231
  const calls = [];
163
232
  const visit = (child) => {
164
- if (ts.isCallExpression(child)) {
233
+ if (ts2.isCallExpression(child)) {
165
234
  const callee = child.expression.getText(sourceFile);
166
235
  if (/^fetch\.[a-z]/.test(callee) || /^st\.do\.(init|get|view|load|list|count|insight)[A-Z]/.test(callee))
167
236
  calls.push({ callee, node: child });
168
237
  }
169
- ts.forEachChild(child, visit);
238
+ ts2.forEachChild(child, visit);
170
239
  };
171
- ts.forEachChild(node, visit);
240
+ ts2.forEachChild(node, visit);
172
241
  return calls;
173
242
  }
174
243
  #getTemplateStateWarnings(sourceFile) {
@@ -176,7 +245,7 @@ class SsrScanner {
176
245
  return [];
177
246
  const warnings = [];
178
247
  const visit = (node) => {
179
- if (ts.isCallExpression(node) && node.expression.getText(sourceFile.sourceFile) === "useState") {
248
+ if (ts2.isCallExpression(node) && node.expression.getText(sourceFile.sourceFile) === "useState") {
180
249
  warnings.push({
181
250
  rule: "akan.ssr.template-client-state",
182
251
  scope: "ssr",
@@ -186,9 +255,9 @@ class SsrScanner {
186
255
  message: "Template holds form state in useState. Templates are store-driven and carry no local state."
187
256
  });
188
257
  }
189
- ts.forEachChild(node, visit);
258
+ ts2.forEachChild(node, visit);
190
259
  };
191
- ts.forEachChild(sourceFile.sourceFile, visit);
260
+ ts2.forEachChild(sourceFile.sourceFile, visit);
192
261
  return warnings;
193
262
  }
194
263
  #measureBalance(sourceFiles) {
@@ -229,14 +298,14 @@ class SsrScanner {
229
298
  return components;
230
299
  }
231
300
  #getComponentNodes(statement) {
232
- if (ts.isFunctionDeclaration(statement) && statement.body)
301
+ if (ts2.isFunctionDeclaration(statement) && statement.body)
233
302
  return [{ name: statement.name?.text ?? "default", node: statement.body }];
234
- if (!ts.isVariableStatement(statement))
303
+ if (!ts2.isVariableStatement(statement))
235
304
  return [];
236
305
  return statement.declarationList.declarations.flatMap((declaration) => {
237
- if (!ts.isIdentifier(declaration.name) || !declaration.initializer)
306
+ if (!ts2.isIdentifier(declaration.name) || !declaration.initializer)
238
307
  return [];
239
- if (!ts.isArrowFunction(declaration.initializer) && !ts.isFunctionExpression(declaration.initializer))
308
+ if (!ts2.isArrowFunction(declaration.initializer) && !ts2.isFunctionExpression(declaration.initializer))
240
309
  return [];
241
310
  return [{ name: declaration.name.text, node: declaration.initializer }];
242
311
  });
@@ -244,7 +313,7 @@ class SsrScanner {
244
313
  #getTouches(sourceFile, node) {
245
314
  const touches = [];
246
315
  const visit = (child) => {
247
- if (ts.isCallExpression(child)) {
316
+ if (ts2.isCallExpression(child)) {
248
317
  const callee = child.expression.getText(sourceFile);
249
318
  const bareName = callee.split(".").pop() ?? callee;
250
319
  if (callee === "createContext" || callee === "lazy")
@@ -252,60 +321,60 @@ class SsrScanner {
252
321
  else if (/^use[A-Z]/.test(bareName) && !SsrScanner.#serverSafeCalls.has(bareName))
253
322
  touches.push(bareName);
254
323
  }
255
- if (ts.isJsxAttribute(child) && /^on[A-Z]/.test(child.name.getText(sourceFile)))
324
+ if (ts2.isJsxAttribute(child) && /^on[A-Z]/.test(child.name.getText(sourceFile)))
256
325
  touches.push(child.name.getText(sourceFile));
257
- if (ts.isPropertyAccessExpression(child)) {
326
+ if (ts2.isPropertyAccessExpression(child)) {
258
327
  const root = getAccessRoot(child);
259
328
  if (root === "st")
260
329
  touches.push("st");
261
330
  else if (SsrScanner.#clientGlobals.has(root))
262
331
  touches.push(root);
263
332
  }
264
- ts.forEachChild(child, visit);
333
+ ts2.forEachChild(child, visit);
265
334
  };
266
- ts.forEachChild(node, visit);
335
+ ts2.forEachChild(node, visit);
267
336
  return touches;
268
337
  }
269
338
  #getTagNames(sourceFile, node) {
270
339
  const tags = new Set;
271
340
  const visit = (child) => {
272
- if (ts.isJsxOpeningElement(child) || ts.isJsxSelfClosingElement(child))
341
+ if (ts2.isJsxOpeningElement(child) || ts2.isJsxSelfClosingElement(child))
273
342
  tags.add(child.tagName.getText(sourceFile).split(".")[0]);
274
- ts.forEachChild(child, visit);
343
+ ts2.forEachChild(child, visit);
275
344
  };
276
- ts.forEachChild(node, visit);
345
+ ts2.forEachChild(node, visit);
277
346
  return tags;
278
347
  }
279
348
  #getMass(node) {
280
349
  let mass = 0;
281
350
  const visit = (child) => {
282
- if (ts.isJsxOpeningElement(child) || ts.isJsxSelfClosingElement(child))
351
+ if (ts2.isJsxOpeningElement(child) || ts2.isJsxSelfClosingElement(child))
283
352
  mass += 1;
284
- ts.forEachChild(child, visit);
353
+ ts2.forEachChild(child, visit);
285
354
  };
286
- ts.forEachChild(node, visit);
355
+ ts2.forEachChild(node, visit);
287
356
  return mass;
288
357
  }
289
358
  #hasUseClient(sourceFile) {
290
359
  const first = sourceFile.statements[0];
291
- if (!first || !ts.isExpressionStatement(first) || !ts.isStringLiteral(first.expression))
360
+ if (!first || !ts2.isExpressionStatement(first) || !ts2.isStringLiteral(first.expression))
292
361
  return false;
293
362
  return first.expression.text === "use client";
294
363
  }
295
364
  #hasVendorImport(sourceFile) {
296
- return sourceFile.statements.some((statement) => ts.isImportDeclaration(statement) && isVendorSpecifier(getSpecifier(statement)));
365
+ return sourceFile.statements.some((statement) => ts2.isImportDeclaration(statement) && isVendorSpecifier(getSpecifier(statement)));
297
366
  }
298
367
  #getVendorNames(sourceFile) {
299
368
  const names = new Set;
300
369
  for (const statement of sourceFile.statements) {
301
- if (!ts.isImportDeclaration(statement) || !isVendorSpecifier(getSpecifier(statement)))
370
+ if (!ts2.isImportDeclaration(statement) || !isVendorSpecifier(getSpecifier(statement)))
302
371
  continue;
303
372
  const clause = statement.importClause;
304
373
  if (clause?.name)
305
374
  names.add(clause.name.text);
306
- if (clause?.namedBindings && ts.isNamespaceImport(clause.namedBindings))
375
+ if (clause?.namedBindings && ts2.isNamespaceImport(clause.namedBindings))
307
376
  names.add(clause.namedBindings.name.text);
308
- if (clause?.namedBindings && ts.isNamedImports(clause.namedBindings))
377
+ if (clause?.namedBindings && ts2.isNamedImports(clause.namedBindings))
309
378
  for (const element of clause.namedBindings.elements)
310
379
  names.add(element.name.text);
311
380
  }
@@ -313,10 +382,10 @@ class SsrScanner {
313
382
  }
314
383
  #importsClientRuntime(sourceFile) {
315
384
  for (const statement of sourceFile.statements) {
316
- if (!ts.isImportDeclaration(statement))
385
+ if (!ts2.isImportDeclaration(statement))
317
386
  continue;
318
387
  const bindings = statement.importClause?.namedBindings;
319
- if (!bindings || !ts.isNamedImports(bindings))
388
+ if (!bindings || !ts2.isNamedImports(bindings))
320
389
  continue;
321
390
  if (bindings.elements.some((element) => SsrScanner.#clientRuntimeImports.has(element.name.text)))
322
391
  return true;
@@ -367,7 +436,7 @@ function getShare(serverMass, clientMass) {
367
436
  return total === 0 ? 1 : serverMass / total;
368
437
  }
369
438
  function getSpecifier(statement) {
370
- return ts.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : "";
439
+ return ts2.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : "";
371
440
  }
372
441
  function isVendorSpecifier(specifier) {
373
442
  if (specifier === "" || specifier.startsWith(".") || specifier.startsWith("/"))
@@ -380,9 +449,9 @@ function isVendorSpecifier(specifier) {
380
449
  }
381
450
  function getAccessRoot(node) {
382
451
  let current = node;
383
- while (ts.isPropertyAccessExpression(current))
452
+ while (ts2.isPropertyAccessExpression(current))
384
453
  current = current.expression;
385
- return ts.isIdentifier(current) ? current.text : "";
454
+ return ts2.isIdentifier(current) ? current.text : "";
386
455
  }
387
456
 
388
457
  // pkgs/@akanjs/devkit/qualityScanner.ts
@@ -406,6 +475,7 @@ var SUGGESTED_RULES = [
406
475
  "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
476
  "Use domain module folders consistently: lib/<model> for database modules, lib/_<service> for service modules, and lib/__scalar/<scalar> for scalar modules.",
408
477
  "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.",
478
+ "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 store action of the same name.",
409
479
  "Move shared app utilities to apps/*/common instead of creating apps/*/base.",
410
480
  "Avoid large mixed-purpose class files; class export files should import helpers from neighboring utility files instead of declaring them inline."
411
481
  ];
@@ -429,6 +499,7 @@ var RULE_FIXES = {
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 store action named set<Field>On<Model> that writes through super.set<Field>On<Model>(v).",
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).",
@@ -460,6 +531,7 @@ class AkanQualityScanner {
460
531
  ...sourceFiles.flatMap((sourceFile) => this.#scanConventionQuality(sourceFile)),
461
532
  ...sourceFiles.flatMap((sourceFile) => this.#scanLayoutQuality(sourceFile)),
462
533
  ...abstractFiles.flatMap((abstractFile) => this.#scanAbstractQuality(abstractFile)),
534
+ ...new FormSetterScanner().scan(sourceFiles),
463
535
  ...ssr.warnings
464
536
  ];
465
537
  return {
@@ -512,7 +584,7 @@ class AkanQualityScanner {
512
584
  file,
513
585
  absolutePath,
514
586
  content,
515
- sourceFile: ts2.createSourceFile(file, content, ts2.ScriptTarget.Latest, true, getScriptKind(file))
587
+ sourceFile: ts3.createSourceFile(file, content, ts3.ScriptTarget.Latest, true, getScriptKind(file))
516
588
  };
517
589
  }
518
590
  async#readTextFile(workspaceRoot, file) {
@@ -759,7 +831,7 @@ function getExportedFunctionLikes(sourceFile) {
759
831
  const declarations = [];
760
832
  const nameExempt = isPageRouteFile(sourceFile.file) || isUiComponentFile(sourceFile.file);
761
833
  for (const statement of sourceFile.sourceFile.statements) {
762
- if (ts2.isFunctionDeclaration(statement) && statement.name && isExported(statement)) {
834
+ if (ts3.isFunctionDeclaration(statement) && statement.name && isExported(statement)) {
763
835
  declarations.push({
764
836
  name: statement.name.text,
765
837
  kind: "function",
@@ -769,7 +841,7 @@ function getExportedFunctionLikes(sourceFile) {
769
841
  duplicateNameExempt: nameExempt || isConventionDuplicateNameExempt(sourceFile.file, false)
770
842
  });
771
843
  }
772
- if (ts2.isClassDeclaration(statement) && statement.name && isExported(statement)) {
844
+ if (ts3.isClassDeclaration(statement) && statement.name && isExported(statement)) {
773
845
  declarations.push({
774
846
  name: statement.name.text,
775
847
  kind: "class",
@@ -779,9 +851,9 @@ function getExportedFunctionLikes(sourceFile) {
779
851
  duplicateNameExempt: nameExempt || isConventionDuplicateNameExempt(sourceFile.file, isEnumClassStatement(sourceFile.sourceFile, statement))
780
852
  });
781
853
  }
782
- if (ts2.isVariableStatement(statement) && isExported(statement)) {
854
+ if (ts3.isVariableStatement(statement) && isExported(statement)) {
783
855
  for (const declaration of statement.declarationList.declarations) {
784
- if (!ts2.isIdentifier(declaration.name) || !isFunctionLikeInitializer(declaration.initializer))
856
+ if (!ts3.isIdentifier(declaration.name) || !isFunctionLikeInitializer(declaration.initializer))
785
857
  continue;
786
858
  declarations.push({
787
859
  name: declaration.name.text,
@@ -820,14 +892,14 @@ function isInLibModule(file) {
820
892
  return (segments[0] === "apps" || segments[0] === "libs") && segments.includes("lib");
821
893
  }
822
894
  function isEnumClassStatement(sourceFile, statement) {
823
- if (!ts2.isClassDeclaration(statement))
895
+ if (!ts3.isClassDeclaration(statement))
824
896
  return false;
825
- const heritageClause = statement.heritageClauses?.find((clause) => clause.token === ts2.SyntaxKind.ExtendsKeyword);
897
+ const heritageClause = statement.heritageClauses?.find((clause) => clause.token === ts3.SyntaxKind.ExtendsKeyword);
826
898
  const expression = heritageClause?.types[0]?.expression;
827
899
  return !!expression && expression.getText(sourceFile).startsWith("enumOf(");
828
900
  }
829
901
  function getExportedClassNames(sourceFile) {
830
- return sourceFile.statements.filter((statement) => ts2.isClassDeclaration(statement) && !!statement.name).filter((statement) => isExported(statement)).map((statement) => statement.name.text);
902
+ return sourceFile.statements.filter((statement) => ts3.isClassDeclaration(statement) && !!statement.name).filter((statement) => isExported(statement)).map((statement) => statement.name.text);
831
903
  }
832
904
  function isComponentDeclarationFile(file) {
833
905
  if (!file.endsWith(".tsx"))
@@ -843,7 +915,7 @@ function isComponentDeclarationFile(file) {
843
915
  function getComponentFileDeclarations(sourceFile) {
844
916
  const reExportedNames = new Set;
845
917
  for (const statement of sourceFile.statements) {
846
- if (ts2.isExportDeclaration(statement) && statement.exportClause && ts2.isNamedExports(statement.exportClause)) {
918
+ if (ts3.isExportDeclaration(statement) && statement.exportClause && ts3.isNamedExports(statement.exportClause)) {
847
919
  for (const element of statement.exportClause.elements)
848
920
  reExportedNames.add((element.propertyName ?? element.name).text);
849
921
  }
@@ -853,19 +925,19 @@ function getComponentFileDeclarations(sourceFile) {
853
925
  const isDefaultExport = isDefaultExportStatement(statement);
854
926
  const inlineExported = isExported(statement);
855
927
  const add = (name, kind, line) => declarations.push({ name, kind, line, exported: inlineExported || reExportedNames.has(name), isDefaultExport });
856
- if (ts2.isInterfaceDeclaration(statement))
928
+ if (ts3.isInterfaceDeclaration(statement))
857
929
  add(statement.name.text, "interface", getLine(sourceFile, statement));
858
- else if (ts2.isTypeAliasDeclaration(statement))
930
+ else if (ts3.isTypeAliasDeclaration(statement))
859
931
  add(statement.name.text, "type", getLine(sourceFile, statement));
860
- else if (ts2.isEnumDeclaration(statement))
932
+ else if (ts3.isEnumDeclaration(statement))
861
933
  add(statement.name.text, "enum", getLine(sourceFile, statement));
862
- else if (ts2.isFunctionDeclaration(statement) && statement.name)
934
+ else if (ts3.isFunctionDeclaration(statement) && statement.name)
863
935
  add(statement.name.text, "function", getLine(sourceFile, statement));
864
- else if (ts2.isClassDeclaration(statement) && statement.name)
936
+ else if (ts3.isClassDeclaration(statement) && statement.name)
865
937
  add(statement.name.text, "class", getLine(sourceFile, statement));
866
- else if (ts2.isVariableStatement(statement)) {
938
+ else if (ts3.isVariableStatement(statement)) {
867
939
  for (const declaration of statement.declarationList.declarations) {
868
- if (!ts2.isIdentifier(declaration.name))
940
+ if (!ts3.isIdentifier(declaration.name))
869
941
  continue;
870
942
  const kind = isFunctionLikeInitializer(declaration.initializer) ? "function" : "variable";
871
943
  add(declaration.name.text, kind, getLine(sourceFile, declaration));
@@ -877,15 +949,15 @@ function getComponentFileDeclarations(sourceFile) {
877
949
  function getCompoundComponentNames(sourceFile) {
878
950
  const names = new Set;
879
951
  for (const statement of sourceFile.statements) {
880
- if (!ts2.isExpressionStatement(statement))
952
+ if (!ts3.isExpressionStatement(statement))
881
953
  continue;
882
954
  const { expression } = statement;
883
- if (!ts2.isBinaryExpression(expression) || expression.operatorToken.kind !== ts2.SyntaxKind.EqualsToken)
955
+ if (!ts3.isBinaryExpression(expression) || expression.operatorToken.kind !== ts3.SyntaxKind.EqualsToken)
884
956
  continue;
885
- if (!ts2.isPropertyAccessExpression(expression.left) || !isPascalCaseName(expression.left.name.text))
957
+ if (!ts3.isPropertyAccessExpression(expression.left) || !isPascalCaseName(expression.left.name.text))
886
958
  continue;
887
959
  names.add(expression.left.name.text);
888
- if (ts2.isIdentifier(expression.right) && isPascalCaseName(expression.right.text))
960
+ if (ts3.isIdentifier(expression.right) && isPascalCaseName(expression.right.text))
889
961
  names.add(expression.right.text);
890
962
  }
891
963
  return names;
@@ -905,9 +977,9 @@ function isPascalCaseName(name) {
905
977
  return /^[A-Z]/.test(name) && !/^[A-Z0-9_]+$/.test(name);
906
978
  }
907
979
  function isDefaultExportStatement(statement) {
908
- if (ts2.isExportAssignment(statement))
980
+ if (ts3.isExportAssignment(statement))
909
981
  return !statement.isExportEquals;
910
- return !!(ts2.getCombinedModifierFlags(statement) & ts2.ModifierFlags.Default);
982
+ return !!(ts3.getCombinedModifierFlags(statement) & ts3.ModifierFlags.Default);
911
983
  }
912
984
  function getPlaceholderExportWarnings(sourceFile) {
913
985
  if (!sourceFile.file.endsWith("/index.ts") && !sourceFile.file.endsWith("/index.tsx"))
@@ -937,7 +1009,7 @@ function getDictionaryTextWarnings(sourceFile) {
937
1009
  function getGlobalMutationWarnings(sourceFile) {
938
1010
  const warnings = [];
939
1011
  for (const statement of sourceFile.sourceFile.statements) {
940
- if (ts2.isModuleDeclaration(statement) && statement.name.getText(sourceFile.sourceFile) === "global") {
1012
+ if (ts3.isModuleDeclaration(statement) && statement.name.getText(sourceFile.sourceFile) === "global") {
941
1013
  warnings.push({
942
1014
  rule: "akan.file.global-declaration",
943
1015
  scope: "file",
@@ -947,7 +1019,7 @@ function getGlobalMutationWarnings(sourceFile) {
947
1019
  message: "Global declarations require an explicit low-level integration allowlist."
948
1020
  });
949
1021
  }
950
- if (ts2.isInterfaceDeclaration(statement) && statement.name.text === "Window") {
1022
+ if (ts3.isInterfaceDeclaration(statement) && statement.name.text === "Window") {
951
1023
  warnings.push({
952
1024
  rule: "akan.file.window-augmentation",
953
1025
  scope: "file",
@@ -957,7 +1029,7 @@ function getGlobalMutationWarnings(sourceFile) {
957
1029
  message: "Window augmentation should be isolated to approved browser integration files."
958
1030
  });
959
1031
  }
960
- if (ts2.isExpressionStatement(statement) && statement.expression.getText(sourceFile.sourceFile).includes(".prototype.")) {
1032
+ if (ts3.isExpressionStatement(statement) && statement.expression.getText(sourceFile.sourceFile).includes(".prototype.")) {
961
1033
  warnings.push({
962
1034
  rule: "akan.file.prototype-mutation",
963
1035
  scope: "file",
@@ -975,23 +1047,23 @@ function getTopLevelDeclarations(sourceFile) {
975
1047
  }
976
1048
  function getTopLevelDeclaration(sourceFile, statement) {
977
1049
  const line = getLine(sourceFile, statement);
978
- if (ts2.isClassDeclaration(statement) && statement.name) {
1050
+ if (ts3.isClassDeclaration(statement) && statement.name) {
979
1051
  return [{ name: statement.name.text, kind: "class", line, exported: isExported(statement), node: statement }];
980
1052
  }
981
- if (ts2.isFunctionDeclaration(statement) && statement.name) {
1053
+ if (ts3.isFunctionDeclaration(statement) && statement.name) {
982
1054
  return [{ name: statement.name.text, kind: "function", line, exported: isExported(statement), node: statement }];
983
1055
  }
984
- if (ts2.isInterfaceDeclaration(statement)) {
1056
+ if (ts3.isInterfaceDeclaration(statement)) {
985
1057
  return [{ name: statement.name.text, kind: "interface", line, exported: isExported(statement), node: statement }];
986
1058
  }
987
- if (ts2.isTypeAliasDeclaration(statement)) {
1059
+ if (ts3.isTypeAliasDeclaration(statement)) {
988
1060
  return [{ name: statement.name.text, kind: "type", line, exported: isExported(statement), node: statement }];
989
1061
  }
990
- if (ts2.isEnumDeclaration(statement)) {
1062
+ if (ts3.isEnumDeclaration(statement)) {
991
1063
  return [{ name: statement.name.text, kind: "enum", line, exported: isExported(statement), node: statement }];
992
1064
  }
993
- if (ts2.isVariableStatement(statement)) {
994
- return statement.declarationList.declarations.filter((declaration) => ts2.isIdentifier(declaration.name)).map((declaration) => ({
1065
+ if (ts3.isVariableStatement(statement)) {
1066
+ return statement.declarationList.declarations.filter((declaration) => ts3.isIdentifier(declaration.name)).map((declaration) => ({
995
1067
  name: declaration.name.text,
996
1068
  kind: "variable",
997
1069
  line: getLine(sourceFile, declaration),
@@ -999,7 +1071,7 @@ function getTopLevelDeclaration(sourceFile, statement) {
999
1071
  node: statement
1000
1072
  }));
1001
1073
  }
1002
- if (ts2.isExportDeclaration(statement)) {
1074
+ if (ts3.isExportDeclaration(statement)) {
1003
1075
  return [{ name: "export declaration", kind: "export", line, exported: true, node: statement }];
1004
1076
  }
1005
1077
  return [];
@@ -1024,9 +1096,9 @@ function isAllowedConstantDeclaration(modelName, declaration) {
1024
1096
  return false;
1025
1097
  if ([`${modelName}Input`, `${modelName}Object`, modelName, `Light${modelName}`, `${modelName}Insight`].includes(declaration.name))
1026
1098
  return true;
1027
- if (!ts2.isClassDeclaration(declaration.node))
1099
+ if (!ts3.isClassDeclaration(declaration.node))
1028
1100
  return false;
1029
- const heritageClause = declaration.node.heritageClauses?.find((clause) => clause.token === ts2.SyntaxKind.ExtendsKeyword);
1101
+ const heritageClause = declaration.node.heritageClauses?.find((clause) => clause.token === ts3.SyntaxKind.ExtendsKeyword);
1030
1102
  const expression = heritageClause?.types[0]?.expression;
1031
1103
  return !!expression && expression.getText().startsWith("enumOf(");
1032
1104
  }
@@ -1092,13 +1164,13 @@ function getModuleInfo(file) {
1092
1164
  return { moduleName, fileName, kind: "database" };
1093
1165
  }
1094
1166
  function isExportedConst(declaration) {
1095
- return declaration.exported && ts2.isVariableStatement(declaration.node) && (declaration.node.declarationList.flags & ts2.NodeFlags.Const) !== 0;
1167
+ return declaration.exported && ts3.isVariableStatement(declaration.node) && (declaration.node.declarationList.flags & ts3.NodeFlags.Const) !== 0;
1096
1168
  }
1097
1169
  function isExported(node) {
1098
- return !!ts2.getCombinedModifierFlags(node) && !!(ts2.getCombinedModifierFlags(node) & ts2.ModifierFlags.Export);
1170
+ return !!ts3.getCombinedModifierFlags(node) && !!(ts3.getCombinedModifierFlags(node) & ts3.ModifierFlags.Export);
1099
1171
  }
1100
1172
  function isFunctionLikeInitializer(node) {
1101
- return !!node && (ts2.isArrowFunction(node) || ts2.isFunctionExpression(node));
1173
+ return !!node && (ts3.isArrowFunction(node) || ts3.isFunctionExpression(node));
1102
1174
  }
1103
1175
  function getBodyFingerprint(sourceFile, node) {
1104
1176
  if (!node)
@@ -1120,7 +1192,7 @@ async function isDirectory(absolutePath) {
1120
1192
  }
1121
1193
  }
1122
1194
  function getScriptKind(file) {
1123
- return file.endsWith(".tsx") ? ts2.ScriptKind.TSX : ts2.ScriptKind.TS;
1195
+ return file.endsWith(".tsx") ? ts3.ScriptKind.TSX : ts3.ScriptKind.TS;
1124
1196
  }
1125
1197
  function getLine(sourceFile, node) {
1126
1198
  return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;