@akanjs/cli 3.0.0-alpha.6 → 3.0.0-alpha.60
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 +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/{abstractCompactor-e5yq60qz.js → abstractCompactor-20e0cwbs.js} +2 -2
- package/{agent.command-b0fcx3r2.js → agent.command-tsx1nsdj.js} +9 -7
- package/{application.command-cezdnvtq.js → application.command-n8ex8g9h.js} +8 -6
- package/{applicationBuildRunner-ha3y8ew8.js → applicationBuildRunner-x8h12rp0.js} +7 -7
- package/{applicationReleasePackager-gg8ccbeh.js → applicationReleasePackager-93nzdfsy.js} +1 -1
- package/buildBatch.proc.js +7 -5
- package/{capacitorApp-jaksw4cy.js → capacitorApp-8mv9e537.js} +29 -27
- package/{cloud.command-6xvsd487.js → cloud.command-f0rhw014.js} +12 -10
- package/{context.command-ajn1b683.js → context.command-s7a41qjs.js} +17 -15
- package/{dependencyScanner-f6grrep3.js → dependencyScanner-rbs2407b.js} +1 -1
- package/getDirname-ka11hm7e.js +8 -0
- package/{guideline.command-9ew6aqhm.js → guideline.command-qrw84ttb.js} +8 -6
- package/guidelines/agentRule/agentRule.generate.json +31 -0
- package/guidelines/agentRule/agentRule.instruction.md +525 -0
- package/guidelines/conventions/conventions.generate.json +25 -0
- package/guidelines/conventions/conventions.instruction.md +811 -0
- package/guidelines/cssRule/cssRule.instruction.md +7 -0
- package/guidelines/framework/framework.instruction.md +1 -0
- package/guidelines/mcpRule/mcpRule.generate.json +25 -0
- package/guidelines/mcpRule/mcpRule.instruction.md +176 -0
- package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +24 -0
- package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +638 -0
- package/incrementalBuilder.proc.js +8 -6
- package/{index-zr2wvx69.js → index-0g9ajdz8.js} +6 -6
- package/index-1577bej2.js +7 -0
- package/{index-wrrb8rxk.js → index-4mtyaqj2.js} +4 -4
- package/{index-bjpxzr6s.js → index-5vy2jzar.js} +1 -1
- package/{index-47qxw1tz.js → index-681sx6nt.js} +176 -66
- package/{index-zbx0jheb.js → index-8md8zszv.js} +14 -13
- package/{index-pfrt7qwh.js → index-cc1mgv1f.js} +4 -4
- package/{index-hk9rbcsz.js → index-ce9755av.js} +1 -1
- package/{index-jkynkyfk.js → index-ckpwq052.js} +5 -3
- package/{index-c94nq3c1.js → index-dvg362vq.js} +3 -3
- package/{index-vkqxw0ek.js → index-ek4mkwxp.js} +13 -13
- package/{index-exhpp31y.js → index-f0t3wjyr.js} +15 -7
- package/index-f39512t6.js +255 -0
- package/{index-m4kpmmtj.js → index-g44fykfw.js} +1 -1
- package/{index-nfxq39kj.js → index-h0mnt0b0.js} +37 -6
- package/{index-qp089jp0.js → index-j37qq1f2.js} +1 -1
- package/{index-hrwzz2wf.js → index-kkya2ped.js} +1 -1
- package/{index-j9cxndc0.js → index-qnv0aqmm.js} +9 -6
- package/{index-r7nqv8qj.js → index-r8z20vnj.js} +14 -14
- package/{index-6npsfpxr.js → index-ryns915y.js} +3 -3
- package/{index-0cj2zxbm.js → index-sh01r3pm.js} +1 -1
- package/{index-60a3jfcz.js → index-tn46rr6w.js} +8 -8
- package/{index-jn9vfpwz.js → index-wc19q8mb.js} +54 -15
- package/{index-meh7mmz9.js → index-x1dbhd80.js} +8 -4
- package/{index-qb61h0k7.js → index-xj5b8c0w.js} +193 -565
- package/index.js +21 -19
- package/{library.command-aa1g8nsa.js → library.command-p3jgf5h2.js} +6 -4
- package/{localRegistry.command-jha3sn50.js → localRegistry.command-bms0qn6t.js} +11 -9
- package/{module.command-b1zzgqde.js → module.command-hb3xm07r.js} +10 -8
- package/{package.command-9qv6vr9s.js → package.command-fbpa6r4w.js} +6 -4
- package/package.json +3 -4
- package/{page.command-k16pw244.js → page.command-92vrmw96.js} +6 -4
- package/{primitive.command-s60dn1ae.js → primitive.command-k6b9jfxr.js} +11 -9
- package/{quality.command-p3vaze52.js → quality.command-89vwmjvf.js} +194 -112
- package/{recipeScanner-tghkzrrt.js → recipeScanner-zrzev25x.js} +3 -3
- package/{repair.command-mfv749ha.js → repair.command-nh9jn8rh.js} +8 -6
- package/{routeSourceValidator-cncd92fv.js → routeSourceValidator-7fycdqyv.js} +3 -39
- package/{scalar.command-hs3nwzv1.js → scalar.command-zcsjgvax.js} +9 -7
- package/templates/app/env/env.server.debug.ts.template +1 -5
- package/templates/app/env/env.server.develop.ts.template +1 -5
- package/templates/app/env/env.server.local.ts.template +1 -5
- package/templates/app/env/env.server.main.ts.template +1 -5
- package/templates/app/page/styles.css.template +3 -3
- package/templates/appSample/srvkit/AuthGuard.ts +9 -5
- package/templates/appSample/srvkit/SessionInternalArg.ts +4 -3
- package/templates/crudPages/[__model__Id]/edit/page.tsx +1 -1
- package/templates/crudPages/new/page.tsx +1 -1
- package/templates/crudSinglePage/page.tsx +1 -1
- package/templates/env/_env.server.type.ts +7 -5
- package/templates/lib/db.ts +1 -1
- package/templates/lib/dict.ts +1 -1
- package/templates/lib/sig.ts +1 -1
- package/templates/lib/srv.ts +6 -2
- package/templates/module/__Model__.Util.tsx +1 -1
- package/templates/module/__Model__.Zone.tsx +3 -5
- package/templates/workspaceRoot/AGENTS.md.template +0 -971
- package/templates/workspaceRoot/CLAUDE.md.template +19 -0
- package/templates/workspaceRoot/biome.json.template +4 -239
- package/templates/workspaceRoot/docs/AI-DEVELOPMENT.md.template +10 -14
- package/templates/workspaceRoot/docs/GENERATED.md.template +12 -10
- package/{typeChecker-kravn7ns.js → typeChecker-g6bh0xfv.js} +1 -1
- package/typecheck.proc.js +1 -1
- package/{workflow.command-z0e0fk0z.js → workflow.command-jj0cphfm.js} +16 -14
- package/{workspace.command-3ydyy991.js → workspace.command-ma3g994j.js} +71 -52
- package/templates/workspaceRoot/.cursor/rules/akan-page-routing.mdc.template +0 -43
- package/templates/workspaceRoot/.cursor/rules/akan-sync-conventions.mdc.template +0 -34
- package/templates/workspaceRoot/.cursor/rules/application-test-commands.mdc.template +0 -16
- package/templates/workspaceRoot/.cursor/rules/change-scope.mdc.template +0 -12
- package/templates/workspaceRoot/.cursor/rules/client-server-boundaries.mdc.template +0 -18
- package/templates/workspaceRoot/.cursor/rules/coding-comments.mdc.template +0 -25
- package/templates/workspaceRoot/.cursor/rules/coding-style.mdc.template +0 -44
- package/templates/workspaceRoot/.cursor/rules/domain-module-conventions.mdc.template +0 -17
- package/templates/workspaceRoot/.cursor/rules/format-lint.mdc.template +0 -12
- package/templates/workspaceRoot/.cursor/rules/lint-enforced-rules.mdc.template +0 -18
- package/templates/workspaceRoot/.cursor/rules/module-file-playbook.mdc.template +0 -61
- package/templates/workspaceRoot/.cursor/rules/naming-conventions.mdc.template +0 -15
- package/templates/workspaceRoot/.cursor/rules/react-component-style.mdc.template +0 -21
- package/templates/workspaceRoot/.cursor/rules/repo-overview.mdc.template +0 -17
- package/templates/workspaceRoot/.cursor/rules/scalar-modeling.mdc.template +0 -58
- package/templates/workspaceRoot/.cursor/rules/secrets-and-env.mdc.template +0 -13
- package/templates/workspaceRoot/.cursor/rules/service-signal-conventions.mdc.template +0 -83
- package/templates/workspaceRoot/.cursor/rules/srvkit-adapters-and-guards.mdc.template +0 -50
- package/templates/workspaceRoot/.cursor/rules/ssr-first.mdc.template +0 -59
- package/templates/workspaceRoot/.cursor/rules/typescript-imports.mdc.template +0 -16
- /package/{index-r24hmh0q.js → index-yb2wsc7f.js} +0 -0
|
@@ -7,24 +7,97 @@ import {
|
|
|
7
7
|
command,
|
|
8
8
|
runner,
|
|
9
9
|
script
|
|
10
|
-
} from "./index-
|
|
10
|
+
} from "./index-ckpwq052.js";
|
|
11
11
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
isAllowedLibFacetRootFile,
|
|
13
|
+
rootAllowedDirs,
|
|
14
|
+
rootAllowedFiles
|
|
15
|
+
} from "./index-681sx6nt.js";
|
|
16
|
+
import"./index-f39512t6.js";
|
|
15
17
|
import"./index-mxvakhsm.js";
|
|
18
|
+
import"./index-1577bej2.js";
|
|
16
19
|
import"./index-67546d0j.js";
|
|
17
|
-
import"./index-
|
|
20
|
+
import"./index-yb2wsc7f.js";
|
|
18
21
|
|
|
19
22
|
// pkgs/@akanjs/devkit/qualityScanner.ts
|
|
20
23
|
import { createHash } from "crypto";
|
|
21
24
|
import { readdir, readFile, stat } from "fs/promises";
|
|
22
25
|
import path from "path";
|
|
26
|
+
import { RESERVED_ROUTE_CONFIG_EXPORTS } from "akanjs/common";
|
|
23
27
|
import ignore from "ignore";
|
|
24
|
-
import
|
|
28
|
+
import ts3 from "typescript";
|
|
25
29
|
|
|
26
|
-
// pkgs/@akanjs/devkit/
|
|
30
|
+
// pkgs/@akanjs/devkit/formSetterScanner.ts
|
|
27
31
|
import ts from "typescript";
|
|
32
|
+
|
|
33
|
+
class FormSetterScanner {
|
|
34
|
+
static #fieldSetter = /^set[A-Za-z0-9_$]*On[A-Za-z0-9_$]*$/;
|
|
35
|
+
scan(sourceFiles) {
|
|
36
|
+
return sourceFiles.filter((sourceFile) => sourceFile.file.endsWith(".tsx")).flatMap((f) => this.#scanFile(f));
|
|
37
|
+
}
|
|
38
|
+
#scanFile({ file, sourceFile }) {
|
|
39
|
+
const wrapped = [];
|
|
40
|
+
const visit = (node) => {
|
|
41
|
+
if (ts.isJsxAttribute(node)) {
|
|
42
|
+
const setter = FormSetterScanner.#wrappedSetterOf(node);
|
|
43
|
+
if (setter)
|
|
44
|
+
wrapped.push({ setter, line: FormSetterScanner.#lineOf(sourceFile, node) });
|
|
45
|
+
}
|
|
46
|
+
ts.forEachChild(node, visit);
|
|
47
|
+
};
|
|
48
|
+
visit(sourceFile);
|
|
49
|
+
if (!wrapped.length)
|
|
50
|
+
return [];
|
|
51
|
+
const setters = [...new Set(wrapped.map((entry) => entry.setter))].sort();
|
|
52
|
+
return [
|
|
53
|
+
{
|
|
54
|
+
rule: "akan.agent.unpublished-form-setter",
|
|
55
|
+
scope: "agent",
|
|
56
|
+
severity: "warning",
|
|
57
|
+
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(", ")}.`,
|
|
58
|
+
file,
|
|
59
|
+
line: wrapped[0]?.line,
|
|
60
|
+
locations: wrapped.map(({ line }) => ({ file, line }))
|
|
61
|
+
}
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
static #wrappedSetterOf(attribute) {
|
|
65
|
+
if (!ts.isIdentifier(attribute.name) || !/^on[A-Z]/.test(attribute.name.text))
|
|
66
|
+
return null;
|
|
67
|
+
const initializer = attribute.initializer;
|
|
68
|
+
if (!initializer || !ts.isJsxExpression(initializer) || !initializer.expression)
|
|
69
|
+
return null;
|
|
70
|
+
const handler = initializer.expression;
|
|
71
|
+
if (!ts.isArrowFunction(handler) && !ts.isFunctionExpression(handler))
|
|
72
|
+
return null;
|
|
73
|
+
if (!handler.parameters.length)
|
|
74
|
+
return null;
|
|
75
|
+
return FormSetterScanner.#setterCallIn(handler.body);
|
|
76
|
+
}
|
|
77
|
+
static #setterCallIn(node) {
|
|
78
|
+
let found = null;
|
|
79
|
+
const visit = (current) => {
|
|
80
|
+
if (found)
|
|
81
|
+
return;
|
|
82
|
+
if (ts.isCallExpression(current) && ts.isPropertyAccessExpression(current.expression)) {
|
|
83
|
+
const { expression, name } = current.expression;
|
|
84
|
+
if (ts.isPropertyAccessExpression(expression) && ts.isIdentifier(expression.expression) && expression.expression.text === "st" && expression.name.text === "do" && FormSetterScanner.#fieldSetter.test(name.text)) {
|
|
85
|
+
found = name.text;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
ts.forEachChild(current, visit);
|
|
90
|
+
};
|
|
91
|
+
visit(node);
|
|
92
|
+
return found;
|
|
93
|
+
}
|
|
94
|
+
static #lineOf(sourceFile, node) {
|
|
95
|
+
return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// pkgs/@akanjs/devkit/ssrScanner.ts
|
|
100
|
+
import ts2 from "typescript";
|
|
28
101
|
var STATIC_COMPONENT_MIN_MASS = 4;
|
|
29
102
|
var MIXED_COMPONENT_MIN_MASS = 10;
|
|
30
103
|
var MIXED_COMPONENT_MAX_TOUCHES = 2;
|
|
@@ -142,31 +215,31 @@ class SsrScanner {
|
|
|
142
215
|
});
|
|
143
216
|
}
|
|
144
217
|
}
|
|
145
|
-
|
|
218
|
+
ts2.forEachChild(node, visit);
|
|
146
219
|
};
|
|
147
|
-
|
|
220
|
+
ts2.forEachChild(sourceFile.sourceFile, visit);
|
|
148
221
|
return warnings;
|
|
149
222
|
}
|
|
150
223
|
#isMountEffect(sourceFile, node) {
|
|
151
|
-
if (!
|
|
224
|
+
if (!ts2.isCallExpression(node))
|
|
152
225
|
return false;
|
|
153
226
|
const callee = node.expression.getText(sourceFile);
|
|
154
227
|
if (callee !== "useEffect" && callee !== "useLayoutEffect")
|
|
155
228
|
return false;
|
|
156
229
|
const deps = node.arguments[1];
|
|
157
|
-
return !!deps &&
|
|
230
|
+
return !!deps && ts2.isArrayLiteralExpression(deps) && deps.elements.length === 0;
|
|
158
231
|
}
|
|
159
232
|
#getLoadCalls(sourceFile, node) {
|
|
160
233
|
const calls = [];
|
|
161
234
|
const visit = (child) => {
|
|
162
|
-
if (
|
|
235
|
+
if (ts2.isCallExpression(child)) {
|
|
163
236
|
const callee = child.expression.getText(sourceFile);
|
|
164
237
|
if (/^fetch\.[a-z]/.test(callee) || /^st\.do\.(init|get|view|load|list|count|insight)[A-Z]/.test(callee))
|
|
165
238
|
calls.push({ callee, node: child });
|
|
166
239
|
}
|
|
167
|
-
|
|
240
|
+
ts2.forEachChild(child, visit);
|
|
168
241
|
};
|
|
169
|
-
|
|
242
|
+
ts2.forEachChild(node, visit);
|
|
170
243
|
return calls;
|
|
171
244
|
}
|
|
172
245
|
#getTemplateStateWarnings(sourceFile) {
|
|
@@ -174,7 +247,7 @@ class SsrScanner {
|
|
|
174
247
|
return [];
|
|
175
248
|
const warnings = [];
|
|
176
249
|
const visit = (node) => {
|
|
177
|
-
if (
|
|
250
|
+
if (ts2.isCallExpression(node) && node.expression.getText(sourceFile.sourceFile) === "useState") {
|
|
178
251
|
warnings.push({
|
|
179
252
|
rule: "akan.ssr.template-client-state",
|
|
180
253
|
scope: "ssr",
|
|
@@ -184,9 +257,9 @@ class SsrScanner {
|
|
|
184
257
|
message: "Template holds form state in useState. Templates are store-driven and carry no local state."
|
|
185
258
|
});
|
|
186
259
|
}
|
|
187
|
-
|
|
260
|
+
ts2.forEachChild(node, visit);
|
|
188
261
|
};
|
|
189
|
-
|
|
262
|
+
ts2.forEachChild(sourceFile.sourceFile, visit);
|
|
190
263
|
return warnings;
|
|
191
264
|
}
|
|
192
265
|
#measureBalance(sourceFiles) {
|
|
@@ -227,14 +300,14 @@ class SsrScanner {
|
|
|
227
300
|
return components;
|
|
228
301
|
}
|
|
229
302
|
#getComponentNodes(statement) {
|
|
230
|
-
if (
|
|
303
|
+
if (ts2.isFunctionDeclaration(statement) && statement.body)
|
|
231
304
|
return [{ name: statement.name?.text ?? "default", node: statement.body }];
|
|
232
|
-
if (!
|
|
305
|
+
if (!ts2.isVariableStatement(statement))
|
|
233
306
|
return [];
|
|
234
307
|
return statement.declarationList.declarations.flatMap((declaration) => {
|
|
235
|
-
if (!
|
|
308
|
+
if (!ts2.isIdentifier(declaration.name) || !declaration.initializer)
|
|
236
309
|
return [];
|
|
237
|
-
if (!
|
|
310
|
+
if (!ts2.isArrowFunction(declaration.initializer) && !ts2.isFunctionExpression(declaration.initializer))
|
|
238
311
|
return [];
|
|
239
312
|
return [{ name: declaration.name.text, node: declaration.initializer }];
|
|
240
313
|
});
|
|
@@ -242,7 +315,7 @@ class SsrScanner {
|
|
|
242
315
|
#getTouches(sourceFile, node) {
|
|
243
316
|
const touches = [];
|
|
244
317
|
const visit = (child) => {
|
|
245
|
-
if (
|
|
318
|
+
if (ts2.isCallExpression(child)) {
|
|
246
319
|
const callee = child.expression.getText(sourceFile);
|
|
247
320
|
const bareName = callee.split(".").pop() ?? callee;
|
|
248
321
|
if (callee === "createContext" || callee === "lazy")
|
|
@@ -250,60 +323,60 @@ class SsrScanner {
|
|
|
250
323
|
else if (/^use[A-Z]/.test(bareName) && !SsrScanner.#serverSafeCalls.has(bareName))
|
|
251
324
|
touches.push(bareName);
|
|
252
325
|
}
|
|
253
|
-
if (
|
|
326
|
+
if (ts2.isJsxAttribute(child) && /^on[A-Z]/.test(child.name.getText(sourceFile)))
|
|
254
327
|
touches.push(child.name.getText(sourceFile));
|
|
255
|
-
if (
|
|
328
|
+
if (ts2.isPropertyAccessExpression(child)) {
|
|
256
329
|
const root = getAccessRoot(child);
|
|
257
330
|
if (root === "st")
|
|
258
331
|
touches.push("st");
|
|
259
332
|
else if (SsrScanner.#clientGlobals.has(root))
|
|
260
333
|
touches.push(root);
|
|
261
334
|
}
|
|
262
|
-
|
|
335
|
+
ts2.forEachChild(child, visit);
|
|
263
336
|
};
|
|
264
|
-
|
|
337
|
+
ts2.forEachChild(node, visit);
|
|
265
338
|
return touches;
|
|
266
339
|
}
|
|
267
340
|
#getTagNames(sourceFile, node) {
|
|
268
341
|
const tags = new Set;
|
|
269
342
|
const visit = (child) => {
|
|
270
|
-
if (
|
|
343
|
+
if (ts2.isJsxOpeningElement(child) || ts2.isJsxSelfClosingElement(child))
|
|
271
344
|
tags.add(child.tagName.getText(sourceFile).split(".")[0]);
|
|
272
|
-
|
|
345
|
+
ts2.forEachChild(child, visit);
|
|
273
346
|
};
|
|
274
|
-
|
|
347
|
+
ts2.forEachChild(node, visit);
|
|
275
348
|
return tags;
|
|
276
349
|
}
|
|
277
350
|
#getMass(node) {
|
|
278
351
|
let mass = 0;
|
|
279
352
|
const visit = (child) => {
|
|
280
|
-
if (
|
|
353
|
+
if (ts2.isJsxOpeningElement(child) || ts2.isJsxSelfClosingElement(child))
|
|
281
354
|
mass += 1;
|
|
282
|
-
|
|
355
|
+
ts2.forEachChild(child, visit);
|
|
283
356
|
};
|
|
284
|
-
|
|
357
|
+
ts2.forEachChild(node, visit);
|
|
285
358
|
return mass;
|
|
286
359
|
}
|
|
287
360
|
#hasUseClient(sourceFile) {
|
|
288
361
|
const first = sourceFile.statements[0];
|
|
289
|
-
if (!first || !
|
|
362
|
+
if (!first || !ts2.isExpressionStatement(first) || !ts2.isStringLiteral(first.expression))
|
|
290
363
|
return false;
|
|
291
364
|
return first.expression.text === "use client";
|
|
292
365
|
}
|
|
293
366
|
#hasVendorImport(sourceFile) {
|
|
294
|
-
return sourceFile.statements.some((statement) =>
|
|
367
|
+
return sourceFile.statements.some((statement) => ts2.isImportDeclaration(statement) && isVendorSpecifier(getSpecifier(statement)));
|
|
295
368
|
}
|
|
296
369
|
#getVendorNames(sourceFile) {
|
|
297
370
|
const names = new Set;
|
|
298
371
|
for (const statement of sourceFile.statements) {
|
|
299
|
-
if (!
|
|
372
|
+
if (!ts2.isImportDeclaration(statement) || !isVendorSpecifier(getSpecifier(statement)))
|
|
300
373
|
continue;
|
|
301
374
|
const clause = statement.importClause;
|
|
302
375
|
if (clause?.name)
|
|
303
376
|
names.add(clause.name.text);
|
|
304
|
-
if (clause?.namedBindings &&
|
|
377
|
+
if (clause?.namedBindings && ts2.isNamespaceImport(clause.namedBindings))
|
|
305
378
|
names.add(clause.namedBindings.name.text);
|
|
306
|
-
if (clause?.namedBindings &&
|
|
379
|
+
if (clause?.namedBindings && ts2.isNamedImports(clause.namedBindings))
|
|
307
380
|
for (const element of clause.namedBindings.elements)
|
|
308
381
|
names.add(element.name.text);
|
|
309
382
|
}
|
|
@@ -311,10 +384,10 @@ class SsrScanner {
|
|
|
311
384
|
}
|
|
312
385
|
#importsClientRuntime(sourceFile) {
|
|
313
386
|
for (const statement of sourceFile.statements) {
|
|
314
|
-
if (!
|
|
387
|
+
if (!ts2.isImportDeclaration(statement))
|
|
315
388
|
continue;
|
|
316
389
|
const bindings = statement.importClause?.namedBindings;
|
|
317
|
-
if (!bindings || !
|
|
390
|
+
if (!bindings || !ts2.isNamedImports(bindings))
|
|
318
391
|
continue;
|
|
319
392
|
if (bindings.elements.some((element) => SsrScanner.#clientRuntimeImports.has(element.name.text)))
|
|
320
393
|
return true;
|
|
@@ -365,7 +438,7 @@ function getShare(serverMass, clientMass) {
|
|
|
365
438
|
return total === 0 ? 1 : serverMass / total;
|
|
366
439
|
}
|
|
367
440
|
function getSpecifier(statement) {
|
|
368
|
-
return
|
|
441
|
+
return ts2.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : "";
|
|
369
442
|
}
|
|
370
443
|
function isVendorSpecifier(specifier) {
|
|
371
444
|
if (specifier === "" || specifier.startsWith(".") || specifier.startsWith("/"))
|
|
@@ -378,9 +451,9 @@ function isVendorSpecifier(specifier) {
|
|
|
378
451
|
}
|
|
379
452
|
function getAccessRoot(node) {
|
|
380
453
|
let current = node;
|
|
381
|
-
while (
|
|
454
|
+
while (ts2.isPropertyAccessExpression(current))
|
|
382
455
|
current = current.expression;
|
|
383
|
-
return
|
|
456
|
+
return ts2.isIdentifier(current) ? current.text : "";
|
|
384
457
|
}
|
|
385
458
|
|
|
386
459
|
// pkgs/@akanjs/devkit/qualityScanner.ts
|
|
@@ -404,7 +477,8 @@ var SUGGESTED_RULES = [
|
|
|
404
477
|
"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.",
|
|
405
478
|
"Use domain module folders consistently: lib/<model> for database modules, lib/_<service> for service modules, and lib/__scalar/<scalar> for scalar modules.",
|
|
406
479
|
"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.",
|
|
407
|
-
"
|
|
480
|
+
"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.",
|
|
481
|
+
"Move shared app and lib utilities to common/ instead of creating apps/*/base or libs/*/base.",
|
|
408
482
|
"Avoid large mixed-purpose class files; class export files should import helpers from neighboring utility files instead of declaring them inline."
|
|
409
483
|
];
|
|
410
484
|
var CONVENTION_SUFFIXES = [
|
|
@@ -415,20 +489,6 @@ var CONVENTION_SUFFIXES = [
|
|
|
415
489
|
".signal.ts",
|
|
416
490
|
".store.ts"
|
|
417
491
|
];
|
|
418
|
-
var PAGE_RESERVED_EXPORTS = new Set([
|
|
419
|
-
"pageConfig",
|
|
420
|
-
"head",
|
|
421
|
-
"metadata",
|
|
422
|
-
"generateHead",
|
|
423
|
-
"generateMetadata",
|
|
424
|
-
"fonts",
|
|
425
|
-
"manifest",
|
|
426
|
-
"theme",
|
|
427
|
-
"reconnect",
|
|
428
|
-
"wsConnect",
|
|
429
|
-
"layoutStyle",
|
|
430
|
-
"gaTrackingId"
|
|
431
|
-
]);
|
|
432
492
|
var RULE_FIXES = {
|
|
433
493
|
"akan.global.duplicate-exported-function-name": "Rename one of the exports, or if they are the same thing, extract it into one shared module and import it in both places.",
|
|
434
494
|
"akan.global.duplicate-exported-function-body": "Extract the shared implementation into a single exported helper and import it, instead of copying the body.",
|
|
@@ -441,10 +501,14 @@ var RULE_FIXES = {
|
|
|
441
501
|
"akan.file.window-augmentation": "Move the Window augmentation into an approved browser integration file and keep it isolated.",
|
|
442
502
|
"akan.file.prototype-mutation": "Avoid prototype mutation, or isolate it in an approved low-level integration file.",
|
|
443
503
|
"akan.file.class-export-global-declaration": "Move the helper to a sibling file and import it into the class module.",
|
|
504
|
+
"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.",
|
|
444
505
|
"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`.",
|
|
445
506
|
"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.",
|
|
446
507
|
"akan.layout.app-root-file": "Move the file into a conventional app folder (common, env, lib, page, private, public, script, srvkit, ui, or webkit).",
|
|
447
|
-
"akan.layout.
|
|
508
|
+
"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.",
|
|
509
|
+
"akan.layout.lib-root-file": "Move the file into a conventional lib folder (common, env, lib, page, private, public, srvkit, ui, or webkit).",
|
|
510
|
+
"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.",
|
|
511
|
+
"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.",
|
|
448
512
|
"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.",
|
|
449
513
|
"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.',
|
|
450
514
|
"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.",
|
|
@@ -472,6 +536,7 @@ class AkanQualityScanner {
|
|
|
472
536
|
...sourceFiles.flatMap((sourceFile) => this.#scanConventionQuality(sourceFile)),
|
|
473
537
|
...sourceFiles.flatMap((sourceFile) => this.#scanLayoutQuality(sourceFile)),
|
|
474
538
|
...abstractFiles.flatMap((abstractFile) => this.#scanAbstractQuality(abstractFile)),
|
|
539
|
+
...new FormSetterScanner().scan(sourceFiles),
|
|
475
540
|
...ssr.warnings
|
|
476
541
|
];
|
|
477
542
|
return {
|
|
@@ -524,7 +589,7 @@ class AkanQualityScanner {
|
|
|
524
589
|
file,
|
|
525
590
|
absolutePath,
|
|
526
591
|
content,
|
|
527
|
-
sourceFile:
|
|
592
|
+
sourceFile: ts3.createSourceFile(file, content, ts3.ScriptTarget.Latest, true, getScriptKind(file))
|
|
528
593
|
};
|
|
529
594
|
}
|
|
530
595
|
async#readTextFile(workspaceRoot, file) {
|
|
@@ -683,25 +748,30 @@ class AkanQualityScanner {
|
|
|
683
748
|
];
|
|
684
749
|
}
|
|
685
750
|
#scanLayoutQuality(sourceFile) {
|
|
686
|
-
const segments = sourceFile.file.split("/");
|
|
687
751
|
const warnings = [];
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
752
|
+
const rootEntry = getSysRootEntry(sourceFile.file);
|
|
753
|
+
if (rootEntry) {
|
|
754
|
+
const { type, name, isDir } = rootEntry;
|
|
755
|
+
const allowed = isDir ? rootAllowedDirs[type].has(name) : rootAllowedFiles[type].has(name);
|
|
756
|
+
const kind = isDir ? "folder" : "file";
|
|
757
|
+
if (!allowed) {
|
|
758
|
+
warnings.push({
|
|
759
|
+
rule: `akan.layout.${type}-root-${kind}`,
|
|
760
|
+
scope: "layout",
|
|
761
|
+
severity: "warning",
|
|
762
|
+
file: sourceFile.file,
|
|
763
|
+
message: `Unexpected ${type} root ${kind} "${name}". Keep ${type} code in conventional ${type} folders.`
|
|
764
|
+
});
|
|
765
|
+
}
|
|
696
766
|
}
|
|
697
|
-
const
|
|
698
|
-
if (
|
|
767
|
+
const libFacetFile = getLibFacetRootFile(sourceFile.file);
|
|
768
|
+
if (libFacetFile && !isAllowedLibFacetRootFile(libFacetFile)) {
|
|
699
769
|
warnings.push({
|
|
700
|
-
rule: "akan.layout.lib-
|
|
770
|
+
rule: "akan.layout.lib-facet-file",
|
|
701
771
|
scope: "layout",
|
|
702
772
|
severity: "warning",
|
|
703
773
|
file: sourceFile.file,
|
|
704
|
-
message: `Unexpected lib root file "${
|
|
774
|
+
message: `Unexpected lib facet root file "${libFacetFile}". Keep direct lib/ root files limited to generated support facets.`
|
|
705
775
|
});
|
|
706
776
|
}
|
|
707
777
|
const moduleUiWarning = getModuleUiWarning(sourceFile.file);
|
|
@@ -771,7 +841,7 @@ function getExportedFunctionLikes(sourceFile) {
|
|
|
771
841
|
const declarations = [];
|
|
772
842
|
const nameExempt = isPageRouteFile(sourceFile.file) || isUiComponentFile(sourceFile.file);
|
|
773
843
|
for (const statement of sourceFile.sourceFile.statements) {
|
|
774
|
-
if (
|
|
844
|
+
if (ts3.isFunctionDeclaration(statement) && statement.name && isExported(statement)) {
|
|
775
845
|
declarations.push({
|
|
776
846
|
name: statement.name.text,
|
|
777
847
|
kind: "function",
|
|
@@ -781,7 +851,7 @@ function getExportedFunctionLikes(sourceFile) {
|
|
|
781
851
|
duplicateNameExempt: nameExempt || isConventionDuplicateNameExempt(sourceFile.file, false)
|
|
782
852
|
});
|
|
783
853
|
}
|
|
784
|
-
if (
|
|
854
|
+
if (ts3.isClassDeclaration(statement) && statement.name && isExported(statement)) {
|
|
785
855
|
declarations.push({
|
|
786
856
|
name: statement.name.text,
|
|
787
857
|
kind: "class",
|
|
@@ -791,9 +861,9 @@ function getExportedFunctionLikes(sourceFile) {
|
|
|
791
861
|
duplicateNameExempt: nameExempt || isConventionDuplicateNameExempt(sourceFile.file, isEnumClassStatement(sourceFile.sourceFile, statement))
|
|
792
862
|
});
|
|
793
863
|
}
|
|
794
|
-
if (
|
|
864
|
+
if (ts3.isVariableStatement(statement) && isExported(statement)) {
|
|
795
865
|
for (const declaration of statement.declarationList.declarations) {
|
|
796
|
-
if (!
|
|
866
|
+
if (!ts3.isIdentifier(declaration.name) || !isFunctionLikeInitializer(declaration.initializer))
|
|
797
867
|
continue;
|
|
798
868
|
declarations.push({
|
|
799
869
|
name: declaration.name.text,
|
|
@@ -832,14 +902,14 @@ function isInLibModule(file) {
|
|
|
832
902
|
return (segments[0] === "apps" || segments[0] === "libs") && segments.includes("lib");
|
|
833
903
|
}
|
|
834
904
|
function isEnumClassStatement(sourceFile, statement) {
|
|
835
|
-
if (!
|
|
905
|
+
if (!ts3.isClassDeclaration(statement))
|
|
836
906
|
return false;
|
|
837
|
-
const heritageClause = statement.heritageClauses?.find((clause) => clause.token ===
|
|
907
|
+
const heritageClause = statement.heritageClauses?.find((clause) => clause.token === ts3.SyntaxKind.ExtendsKeyword);
|
|
838
908
|
const expression = heritageClause?.types[0]?.expression;
|
|
839
909
|
return !!expression && expression.getText(sourceFile).startsWith("enumOf(");
|
|
840
910
|
}
|
|
841
911
|
function getExportedClassNames(sourceFile) {
|
|
842
|
-
return sourceFile.statements.filter((statement) =>
|
|
912
|
+
return sourceFile.statements.filter((statement) => ts3.isClassDeclaration(statement) && !!statement.name).filter((statement) => isExported(statement)).map((statement) => statement.name.text);
|
|
843
913
|
}
|
|
844
914
|
function isComponentDeclarationFile(file) {
|
|
845
915
|
if (!file.endsWith(".tsx"))
|
|
@@ -855,7 +925,7 @@ function isComponentDeclarationFile(file) {
|
|
|
855
925
|
function getComponentFileDeclarations(sourceFile) {
|
|
856
926
|
const reExportedNames = new Set;
|
|
857
927
|
for (const statement of sourceFile.statements) {
|
|
858
|
-
if (
|
|
928
|
+
if (ts3.isExportDeclaration(statement) && statement.exportClause && ts3.isNamedExports(statement.exportClause)) {
|
|
859
929
|
for (const element of statement.exportClause.elements)
|
|
860
930
|
reExportedNames.add((element.propertyName ?? element.name).text);
|
|
861
931
|
}
|
|
@@ -865,19 +935,19 @@ function getComponentFileDeclarations(sourceFile) {
|
|
|
865
935
|
const isDefaultExport = isDefaultExportStatement(statement);
|
|
866
936
|
const inlineExported = isExported(statement);
|
|
867
937
|
const add = (name, kind, line) => declarations.push({ name, kind, line, exported: inlineExported || reExportedNames.has(name), isDefaultExport });
|
|
868
|
-
if (
|
|
938
|
+
if (ts3.isInterfaceDeclaration(statement))
|
|
869
939
|
add(statement.name.text, "interface", getLine(sourceFile, statement));
|
|
870
|
-
else if (
|
|
940
|
+
else if (ts3.isTypeAliasDeclaration(statement))
|
|
871
941
|
add(statement.name.text, "type", getLine(sourceFile, statement));
|
|
872
|
-
else if (
|
|
942
|
+
else if (ts3.isEnumDeclaration(statement))
|
|
873
943
|
add(statement.name.text, "enum", getLine(sourceFile, statement));
|
|
874
|
-
else if (
|
|
944
|
+
else if (ts3.isFunctionDeclaration(statement) && statement.name)
|
|
875
945
|
add(statement.name.text, "function", getLine(sourceFile, statement));
|
|
876
|
-
else if (
|
|
946
|
+
else if (ts3.isClassDeclaration(statement) && statement.name)
|
|
877
947
|
add(statement.name.text, "class", getLine(sourceFile, statement));
|
|
878
|
-
else if (
|
|
948
|
+
else if (ts3.isVariableStatement(statement)) {
|
|
879
949
|
for (const declaration of statement.declarationList.declarations) {
|
|
880
|
-
if (!
|
|
950
|
+
if (!ts3.isIdentifier(declaration.name))
|
|
881
951
|
continue;
|
|
882
952
|
const kind = isFunctionLikeInitializer(declaration.initializer) ? "function" : "variable";
|
|
883
953
|
add(declaration.name.text, kind, getLine(sourceFile, declaration));
|
|
@@ -889,15 +959,15 @@ function getComponentFileDeclarations(sourceFile) {
|
|
|
889
959
|
function getCompoundComponentNames(sourceFile) {
|
|
890
960
|
const names = new Set;
|
|
891
961
|
for (const statement of sourceFile.statements) {
|
|
892
|
-
if (!
|
|
962
|
+
if (!ts3.isExpressionStatement(statement))
|
|
893
963
|
continue;
|
|
894
964
|
const { expression } = statement;
|
|
895
|
-
if (!
|
|
965
|
+
if (!ts3.isBinaryExpression(expression) || expression.operatorToken.kind !== ts3.SyntaxKind.EqualsToken)
|
|
896
966
|
continue;
|
|
897
|
-
if (!
|
|
967
|
+
if (!ts3.isPropertyAccessExpression(expression.left) || !isPascalCaseName(expression.left.name.text))
|
|
898
968
|
continue;
|
|
899
969
|
names.add(expression.left.name.text);
|
|
900
|
-
if (
|
|
970
|
+
if (ts3.isIdentifier(expression.right) && isPascalCaseName(expression.right.text))
|
|
901
971
|
names.add(expression.right.text);
|
|
902
972
|
}
|
|
903
973
|
return names;
|
|
@@ -911,15 +981,15 @@ function isRestrictedInternalKind(kind) {
|
|
|
911
981
|
function isAllowedComponentExport(declaration, isPage) {
|
|
912
982
|
if (isComponentValueKind(declaration.kind) && isPascalCaseName(declaration.name))
|
|
913
983
|
return true;
|
|
914
|
-
return isPage &&
|
|
984
|
+
return isPage && RESERVED_ROUTE_CONFIG_EXPORTS.has(declaration.name);
|
|
915
985
|
}
|
|
916
986
|
function isPascalCaseName(name) {
|
|
917
987
|
return /^[A-Z]/.test(name) && !/^[A-Z0-9_]+$/.test(name);
|
|
918
988
|
}
|
|
919
989
|
function isDefaultExportStatement(statement) {
|
|
920
|
-
if (
|
|
990
|
+
if (ts3.isExportAssignment(statement))
|
|
921
991
|
return !statement.isExportEquals;
|
|
922
|
-
return !!(
|
|
992
|
+
return !!(ts3.getCombinedModifierFlags(statement) & ts3.ModifierFlags.Default);
|
|
923
993
|
}
|
|
924
994
|
function getPlaceholderExportWarnings(sourceFile) {
|
|
925
995
|
if (!sourceFile.file.endsWith("/index.ts") && !sourceFile.file.endsWith("/index.tsx"))
|
|
@@ -949,7 +1019,7 @@ function getDictionaryTextWarnings(sourceFile) {
|
|
|
949
1019
|
function getGlobalMutationWarnings(sourceFile) {
|
|
950
1020
|
const warnings = [];
|
|
951
1021
|
for (const statement of sourceFile.sourceFile.statements) {
|
|
952
|
-
if (
|
|
1022
|
+
if (ts3.isModuleDeclaration(statement) && statement.name.getText(sourceFile.sourceFile) === "global") {
|
|
953
1023
|
warnings.push({
|
|
954
1024
|
rule: "akan.file.global-declaration",
|
|
955
1025
|
scope: "file",
|
|
@@ -959,7 +1029,7 @@ function getGlobalMutationWarnings(sourceFile) {
|
|
|
959
1029
|
message: "Global declarations require an explicit low-level integration allowlist."
|
|
960
1030
|
});
|
|
961
1031
|
}
|
|
962
|
-
if (
|
|
1032
|
+
if (ts3.isInterfaceDeclaration(statement) && statement.name.text === "Window") {
|
|
963
1033
|
warnings.push({
|
|
964
1034
|
rule: "akan.file.window-augmentation",
|
|
965
1035
|
scope: "file",
|
|
@@ -969,7 +1039,7 @@ function getGlobalMutationWarnings(sourceFile) {
|
|
|
969
1039
|
message: "Window augmentation should be isolated to approved browser integration files."
|
|
970
1040
|
});
|
|
971
1041
|
}
|
|
972
|
-
if (
|
|
1042
|
+
if (ts3.isExpressionStatement(statement) && statement.expression.getText(sourceFile.sourceFile).includes(".prototype.")) {
|
|
973
1043
|
warnings.push({
|
|
974
1044
|
rule: "akan.file.prototype-mutation",
|
|
975
1045
|
scope: "file",
|
|
@@ -987,23 +1057,23 @@ function getTopLevelDeclarations(sourceFile) {
|
|
|
987
1057
|
}
|
|
988
1058
|
function getTopLevelDeclaration(sourceFile, statement) {
|
|
989
1059
|
const line = getLine(sourceFile, statement);
|
|
990
|
-
if (
|
|
1060
|
+
if (ts3.isClassDeclaration(statement) && statement.name) {
|
|
991
1061
|
return [{ name: statement.name.text, kind: "class", line, exported: isExported(statement), node: statement }];
|
|
992
1062
|
}
|
|
993
|
-
if (
|
|
1063
|
+
if (ts3.isFunctionDeclaration(statement) && statement.name) {
|
|
994
1064
|
return [{ name: statement.name.text, kind: "function", line, exported: isExported(statement), node: statement }];
|
|
995
1065
|
}
|
|
996
|
-
if (
|
|
1066
|
+
if (ts3.isInterfaceDeclaration(statement)) {
|
|
997
1067
|
return [{ name: statement.name.text, kind: "interface", line, exported: isExported(statement), node: statement }];
|
|
998
1068
|
}
|
|
999
|
-
if (
|
|
1069
|
+
if (ts3.isTypeAliasDeclaration(statement)) {
|
|
1000
1070
|
return [{ name: statement.name.text, kind: "type", line, exported: isExported(statement), node: statement }];
|
|
1001
1071
|
}
|
|
1002
|
-
if (
|
|
1072
|
+
if (ts3.isEnumDeclaration(statement)) {
|
|
1003
1073
|
return [{ name: statement.name.text, kind: "enum", line, exported: isExported(statement), node: statement }];
|
|
1004
1074
|
}
|
|
1005
|
-
if (
|
|
1006
|
-
return statement.declarationList.declarations.filter((declaration) =>
|
|
1075
|
+
if (ts3.isVariableStatement(statement)) {
|
|
1076
|
+
return statement.declarationList.declarations.filter((declaration) => ts3.isIdentifier(declaration.name)).map((declaration) => ({
|
|
1007
1077
|
name: declaration.name.text,
|
|
1008
1078
|
kind: "variable",
|
|
1009
1079
|
line: getLine(sourceFile, declaration),
|
|
@@ -1011,7 +1081,7 @@ function getTopLevelDeclaration(sourceFile, statement) {
|
|
|
1011
1081
|
node: statement
|
|
1012
1082
|
}));
|
|
1013
1083
|
}
|
|
1014
|
-
if (
|
|
1084
|
+
if (ts3.isExportDeclaration(statement)) {
|
|
1015
1085
|
return [{ name: "export declaration", kind: "export", line, exported: true, node: statement }];
|
|
1016
1086
|
}
|
|
1017
1087
|
return [];
|
|
@@ -1036,9 +1106,9 @@ function isAllowedConstantDeclaration(modelName, declaration) {
|
|
|
1036
1106
|
return false;
|
|
1037
1107
|
if ([`${modelName}Input`, `${modelName}Object`, modelName, `Light${modelName}`, `${modelName}Insight`].includes(declaration.name))
|
|
1038
1108
|
return true;
|
|
1039
|
-
if (!
|
|
1109
|
+
if (!ts3.isClassDeclaration(declaration.node))
|
|
1040
1110
|
return false;
|
|
1041
|
-
const heritageClause = declaration.node.heritageClauses?.find((clause) => clause.token ===
|
|
1111
|
+
const heritageClause = declaration.node.heritageClauses?.find((clause) => clause.token === ts3.SyntaxKind.ExtendsKeyword);
|
|
1042
1112
|
const expression = heritageClause?.types[0]?.expression;
|
|
1043
1113
|
return !!expression && expression.getText().startsWith("enumOf(");
|
|
1044
1114
|
}
|
|
@@ -1055,7 +1125,19 @@ function getConventionDescription(suffix, modelName) {
|
|
|
1055
1125
|
return `${modelName}Internal, ${modelName}Slice, or ${modelName}Endpoint`;
|
|
1056
1126
|
return `${modelName}Store`;
|
|
1057
1127
|
}
|
|
1058
|
-
|
|
1128
|
+
var sysRootTypes = { apps: "app", libs: "lib" };
|
|
1129
|
+
function getSysRootEntry(file) {
|
|
1130
|
+
const segments = file.split("/");
|
|
1131
|
+
const root = segments[0];
|
|
1132
|
+
const name = segments[2];
|
|
1133
|
+
if (!root || !name || segments.length < 3)
|
|
1134
|
+
return null;
|
|
1135
|
+
const type = sysRootTypes[root];
|
|
1136
|
+
if (!type)
|
|
1137
|
+
return null;
|
|
1138
|
+
return { type, name, isDir: segments.length > 3 };
|
|
1139
|
+
}
|
|
1140
|
+
function getLibFacetRootFile(file) {
|
|
1059
1141
|
const segments = file.split("/");
|
|
1060
1142
|
if ((segments[0] === "libs" || segments[0] === "apps") && segments.length === 4 && segments[2] === "lib")
|
|
1061
1143
|
return segments[3];
|
|
@@ -1104,13 +1186,13 @@ function getModuleInfo(file) {
|
|
|
1104
1186
|
return { moduleName, fileName, kind: "database" };
|
|
1105
1187
|
}
|
|
1106
1188
|
function isExportedConst(declaration) {
|
|
1107
|
-
return declaration.exported &&
|
|
1189
|
+
return declaration.exported && ts3.isVariableStatement(declaration.node) && (declaration.node.declarationList.flags & ts3.NodeFlags.Const) !== 0;
|
|
1108
1190
|
}
|
|
1109
1191
|
function isExported(node) {
|
|
1110
|
-
return !!
|
|
1192
|
+
return !!ts3.getCombinedModifierFlags(node) && !!(ts3.getCombinedModifierFlags(node) & ts3.ModifierFlags.Export);
|
|
1111
1193
|
}
|
|
1112
1194
|
function isFunctionLikeInitializer(node) {
|
|
1113
|
-
return !!node && (
|
|
1195
|
+
return !!node && (ts3.isArrowFunction(node) || ts3.isFunctionExpression(node));
|
|
1114
1196
|
}
|
|
1115
1197
|
function getBodyFingerprint(sourceFile, node) {
|
|
1116
1198
|
if (!node)
|
|
@@ -1132,7 +1214,7 @@ async function isDirectory(absolutePath) {
|
|
|
1132
1214
|
}
|
|
1133
1215
|
}
|
|
1134
1216
|
function getScriptKind(file) {
|
|
1135
|
-
return file.endsWith(".tsx") ?
|
|
1217
|
+
return file.endsWith(".tsx") ? ts3.ScriptKind.TSX : ts3.ScriptKind.TS;
|
|
1136
1218
|
}
|
|
1137
1219
|
function getLine(sourceFile, node) {
|
|
1138
1220
|
return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;
|