@akanjs/devkit 2.3.11-rc.5 → 2.3.11-rc.6
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/package.json +2 -2
- package/qualityScanner.ts +42 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akanjs/devkit",
|
|
3
|
-
"version": "2.3.11-rc.
|
|
3
|
+
"version": "2.3.11-rc.6",
|
|
4
4
|
"sourceType": "module",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"@langchain/openai": "^1.4.6",
|
|
33
33
|
"@tailwindcss/node": "^4.3.0",
|
|
34
34
|
"@trapezedev/project": "^7.1.4",
|
|
35
|
-
"akanjs": "2.3.11-rc.
|
|
35
|
+
"akanjs": "2.3.11-rc.6",
|
|
36
36
|
"chalk": "^5.6.2",
|
|
37
37
|
"commander": "^14.0.3",
|
|
38
38
|
"daisyui": "5.5.23",
|
package/qualityScanner.ts
CHANGED
|
@@ -37,6 +37,7 @@ interface ExportedFunctionLike {
|
|
|
37
37
|
file: string;
|
|
38
38
|
line: number;
|
|
39
39
|
bodyFingerprint?: string;
|
|
40
|
+
duplicateNameExempt: boolean;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
interface TopLevelDeclaration {
|
|
@@ -177,7 +178,8 @@ export class AkanQualityScanner {
|
|
|
177
178
|
const exportedFunctionLikes = sourceFiles.flatMap((sourceFile) => getExportedFunctionLikes(sourceFile));
|
|
178
179
|
const warnings: QualityWarning[] = [];
|
|
179
180
|
|
|
180
|
-
|
|
181
|
+
const nameCheckedDeclarations = exportedFunctionLikes.filter((declaration) => !declaration.duplicateNameExempt);
|
|
182
|
+
for (const [name, declarations] of groupBy(nameCheckedDeclarations, (declaration) => declaration.name)) {
|
|
181
183
|
if (declarations.length < 2) continue;
|
|
182
184
|
warnings.push({
|
|
183
185
|
rule: "akan.global.duplicate-exported-function-name",
|
|
@@ -345,6 +347,7 @@ function formatQualityLocation(file: string | undefined, line: number | undefine
|
|
|
345
347
|
|
|
346
348
|
function getExportedFunctionLikes(sourceFile: SourceFileInfo): ExportedFunctionLike[] {
|
|
347
349
|
const declarations: ExportedFunctionLike[] = [];
|
|
350
|
+
const pageExempt = isPageRouteFile(sourceFile.file);
|
|
348
351
|
for (const statement of sourceFile.sourceFile.statements) {
|
|
349
352
|
if (ts.isFunctionDeclaration(statement) && statement.name && isExported(statement)) {
|
|
350
353
|
declarations.push({
|
|
@@ -353,6 +356,7 @@ function getExportedFunctionLikes(sourceFile: SourceFileInfo): ExportedFunctionL
|
|
|
353
356
|
file: sourceFile.file,
|
|
354
357
|
line: getLine(sourceFile.sourceFile, statement),
|
|
355
358
|
bodyFingerprint: getBodyFingerprint(sourceFile.sourceFile, statement.body),
|
|
359
|
+
duplicateNameExempt: pageExempt || isConventionDuplicateNameExempt(sourceFile.file, false),
|
|
356
360
|
});
|
|
357
361
|
}
|
|
358
362
|
if (ts.isClassDeclaration(statement) && statement.name && isExported(statement)) {
|
|
@@ -362,6 +366,9 @@ function getExportedFunctionLikes(sourceFile: SourceFileInfo): ExportedFunctionL
|
|
|
362
366
|
file: sourceFile.file,
|
|
363
367
|
line: getLine(sourceFile.sourceFile, statement),
|
|
364
368
|
bodyFingerprint: getBodyFingerprint(sourceFile.sourceFile, statement),
|
|
369
|
+
duplicateNameExempt:
|
|
370
|
+
pageExempt ||
|
|
371
|
+
isConventionDuplicateNameExempt(sourceFile.file, isEnumClassStatement(sourceFile.sourceFile, statement)),
|
|
365
372
|
});
|
|
366
373
|
}
|
|
367
374
|
if (ts.isVariableStatement(statement) && isExported(statement)) {
|
|
@@ -373,6 +380,7 @@ function getExportedFunctionLikes(sourceFile: SourceFileInfo): ExportedFunctionL
|
|
|
373
380
|
file: sourceFile.file,
|
|
374
381
|
line: getLine(sourceFile.sourceFile, declaration),
|
|
375
382
|
bodyFingerprint: getBodyFingerprint(sourceFile.sourceFile, declaration.initializer),
|
|
383
|
+
duplicateNameExempt: pageExempt || isConventionDuplicateNameExempt(sourceFile.file, false),
|
|
376
384
|
});
|
|
377
385
|
}
|
|
378
386
|
}
|
|
@@ -380,6 +388,38 @@ function getExportedFunctionLikes(sourceFile: SourceFileInfo): ExportedFunctionL
|
|
|
380
388
|
return declarations;
|
|
381
389
|
}
|
|
382
390
|
|
|
391
|
+
function isPageRouteFile(file: string) {
|
|
392
|
+
const segments = file.split("/");
|
|
393
|
+
return (segments[0] === "apps" || segments[0] === "libs") && segments[2] === "page";
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function isConventionDuplicateNameExempt(file: string, isEnumClass: boolean) {
|
|
397
|
+
if (!isInLibModule(file)) return false;
|
|
398
|
+
if (file.endsWith(".tsx")) return true;
|
|
399
|
+
if (
|
|
400
|
+
file.endsWith(".document.ts") ||
|
|
401
|
+
file.endsWith(".service.ts") ||
|
|
402
|
+
file.endsWith(".signal.ts") ||
|
|
403
|
+
file.endsWith(".store.ts")
|
|
404
|
+
)
|
|
405
|
+
return true;
|
|
406
|
+
// Model view classes may repeat across modules; enum classes must stay uniquely named.
|
|
407
|
+
if (file.endsWith(".constant.ts")) return !isEnumClass;
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function isInLibModule(file: string) {
|
|
412
|
+
const segments = file.split("/");
|
|
413
|
+
return (segments[0] === "apps" || segments[0] === "libs") && segments.includes("lib");
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function isEnumClassStatement(sourceFile: ts.SourceFile, statement: ts.Statement) {
|
|
417
|
+
if (!ts.isClassDeclaration(statement)) return false;
|
|
418
|
+
const heritageClause = statement.heritageClauses?.find((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword);
|
|
419
|
+
const expression = heritageClause?.types[0]?.expression;
|
|
420
|
+
return !!expression && expression.getText(sourceFile).startsWith("enumOf(");
|
|
421
|
+
}
|
|
422
|
+
|
|
383
423
|
function getExportedClassNames(sourceFile: ts.SourceFile) {
|
|
384
424
|
return sourceFile.statements
|
|
385
425
|
.filter((statement): statement is ts.ClassDeclaration => ts.isClassDeclaration(statement) && !!statement.name)
|
|
@@ -403,11 +443,7 @@ function getPlaceholderExportWarnings(sourceFile: SourceFileInfo): QualityWarnin
|
|
|
403
443
|
|
|
404
444
|
function getDictionaryTextWarnings(sourceFile: SourceFileInfo): QualityWarning[] {
|
|
405
445
|
if (!sourceFile.file.endsWith(".dictionary.ts")) return [];
|
|
406
|
-
const stalePatterns = [
|
|
407
|
-
{ pattern: /\b[A-Z][A-Za-z0-9]* description\b/, label: "scaffold description text" },
|
|
408
|
-
{ pattern: /settting/, label: "misspelling: settting" },
|
|
409
|
-
{ pattern: /배너 수/, label: "stale copied Korean domain noun: 배너 수" },
|
|
410
|
-
];
|
|
446
|
+
const stalePatterns = [{ pattern: /\b[A-Z][A-Za-z0-9]* description\b/, label: "scaffold description text" }];
|
|
411
447
|
return stalePatterns.flatMap(({ pattern, label }) =>
|
|
412
448
|
findPatternLines(sourceFile.content, pattern).map((line) => ({
|
|
413
449
|
rule: "akan.file.dictionary-stale-text",
|