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