@archest/vitest 1.0.0 → 1.0.1
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/dist/index.js +13 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +776 -489
- package/dist/index.mjs.map +1 -1
- package/dist/src/core/classes/classCheckExtendClass.d.ts +3 -0
- package/dist/src/core/classes/classCheckHaveMaxCyclomaticComplexity.d.ts +3 -0
- package/dist/src/core/classes/classCheckHaveModifier.d.ts +3 -0
- package/dist/src/core/classes/classCheckHaveNameMatchingFileName.d.ts +3 -0
- package/dist/src/core/classes/classCheckImplementInterface.d.ts +3 -0
- package/dist/src/core/classes/classCheckMatchNamePattern.d.ts +3 -0
- package/dist/src/core/classes/classCheckResideInFolder.d.ts +3 -0
- package/dist/src/core/classes/locateClasses.d.ts +3 -0
- package/dist/src/core/classes/types.d.ts +14 -0
- package/dist/src/core/files/checkDependOnFilesInFolder.d.ts +3 -0
- package/dist/src/core/files/fileCheckBeFreeOfCycles.d.ts +3 -0
- package/dist/src/core/files/fileCheckHaveMaxCyclomaticComplexity.d.ts +3 -0
- package/dist/src/core/files/fileCheckHaveMaxExportedFunctions.d.ts +3 -0
- package/dist/src/core/files/fileCheckHaveMinMaintainabilityIndex.d.ts +3 -0
- package/dist/src/core/files/fileCheckMatchNamePattern.d.ts +3 -0
- package/dist/src/core/files/getFileDependencies.d.ts +2 -0
- package/dist/src/core/files/locateFiles.d.ts +3 -0
- package/dist/src/core/files/types.d.ts +10 -0
- package/dist/src/core/functions/functionCheckHaveExplicitReturnType.d.ts +3 -0
- package/dist/src/core/functions/functionCheckHaveMaxCyclomaticComplexity.d.ts +3 -0
- package/dist/src/core/functions/functionCheckHaveMinMaintainabilityIndex.d.ts +3 -0
- package/dist/src/core/functions/functionCheckHaveModifier.d.ts +3 -0
- package/dist/src/core/functions/functionCheckHaveNameMatchingFileName.d.ts +3 -0
- package/dist/src/core/functions/functionCheckMatchNamePattern.d.ts +3 -0
- package/dist/src/core/functions/locateFunctions.d.ts +3 -0
- package/dist/src/core/functions/types.d.ts +11 -0
- package/dist/src/core/layers/checkLayeredArchitecture.d.ts +3 -0
- package/dist/src/core/layers/createLayeredArchitecture.d.ts +3 -0
- package/dist/src/core/layers/getLayerDependencies.d.ts +2 -0
- package/dist/src/core/layers/layer.d.ts +2 -0
- package/dist/src/core/layers/layerShouldNotBeAccessedByAnyLayer.d.ts +2 -0
- package/dist/src/core/layers/layerShouldOnlyBeAccessedBy.d.ts +2 -0
- package/dist/src/core/layers/types.d.ts +8 -0
- package/dist/src/core/metrics/calculateCyclomaticComplexity.d.ts +2 -0
- package/dist/src/core/metrics/calculateMaintainabilityIndex.d.ts +2 -0
- package/dist/src/core/project/parseProject.d.ts +22 -0
- package/dist/src/core/properties/locateProperties.d.ts +3 -0
- package/dist/src/core/properties/propertyCheckBeReadonly.d.ts +3 -0
- package/dist/src/core/properties/types.d.ts +10 -0
- package/dist/src/core/shared/sharedCheckHaveMaxCyclomaticComplexity.d.ts +1 -0
- package/dist/src/core/shared/sharedCheckHaveMinMaintainabilityIndex.d.ts +1 -0
- package/dist/src/core/shared/sharedCheckHaveModifier.d.ts +2 -0
- package/dist/src/core/shared/sharedCheckHaveNameMatchingFileName.d.ts +2 -0
- package/dist/src/core/shared/sharedCheckMatchNamePattern.d.ts +1 -0
- package/dist/src/core/slices/locateSlices.d.ts +3 -0
- package/dist/src/core/slices/sliceCheckBeFreeOfCycles.d.ts +3 -0
- package/dist/src/core/slices/sliceCheckHaveMaxDistanceFromMainSequence.d.ts +3 -0
- package/dist/src/core/slices/types.d.ts +8 -0
- package/dist/src/core/types.d.ts +7 -0
- package/dist/src/core/utils/ruleBuilder.d.ts +6 -0
- package/dist/src/index.d.ts +34 -8
- package/dist/src/matchers/index.d.ts +5 -0
- package/package.json +1 -1
- package/src/core/classes/classCheckExtendClass.test.ts +30 -0
- package/src/core/classes/classCheckExtendClass.ts +41 -0
- package/src/core/classes/classCheckHaveMaxCyclomaticComplexity.test.ts +8 -0
- package/src/core/classes/classCheckHaveMaxCyclomaticComplexity.ts +35 -0
- package/src/core/classes/classCheckHaveModifier.test.ts +30 -0
- package/src/core/classes/classCheckHaveModifier.ts +17 -0
- package/src/core/classes/classCheckHaveNameMatchingFileName.test.ts +30 -0
- package/src/core/classes/classCheckHaveNameMatchingFileName.ts +15 -0
- package/src/core/classes/classCheckImplementInterface.test.ts +30 -0
- package/src/core/classes/classCheckImplementInterface.ts +43 -0
- package/src/core/classes/classCheckMatchNamePattern.test.ts +8 -0
- package/src/core/classes/classCheckMatchNamePattern.ts +17 -0
- package/src/core/classes/classCheckResideInFolder.test.ts +8 -0
- package/src/core/classes/classCheckResideInFolder.ts +31 -0
- package/src/core/classes/locateClasses.test.ts +13 -0
- package/src/core/classes/locateClasses.ts +127 -0
- package/src/core/classes/types.ts +16 -0
- package/src/core/files/checkDependOnFilesInFolder.test.ts +7 -0
- package/src/core/files/checkDependOnFilesInFolder.ts +36 -0
- package/src/core/files/fileCheckBeFreeOfCycles.test.ts +7 -0
- package/src/core/files/fileCheckBeFreeOfCycles.ts +72 -0
- package/src/core/files/fileCheckHaveMaxCyclomaticComplexity.test.ts +8 -0
- package/src/core/files/fileCheckHaveMaxCyclomaticComplexity.ts +35 -0
- package/src/core/files/fileCheckHaveMaxExportedFunctions.test.ts +32 -0
- package/src/core/files/fileCheckHaveMaxExportedFunctions.ts +45 -0
- package/src/core/files/fileCheckHaveMinMaintainabilityIndex.test.ts +8 -0
- package/src/core/files/fileCheckHaveMinMaintainabilityIndex.ts +19 -0
- package/src/core/files/fileCheckMatchNamePattern.test.ts +30 -0
- package/src/core/files/fileCheckMatchNamePattern.ts +17 -0
- package/src/core/files/getFileDependencies.ts +43 -0
- package/src/core/files/locateFiles.test.ts +30 -0
- package/src/core/files/locateFiles.ts +31 -0
- package/src/core/files/types.ts +12 -0
- package/src/core/functions/functionCheckHaveExplicitReturnType.test.ts +30 -0
- package/src/core/functions/functionCheckHaveExplicitReturnType.ts +29 -0
- package/src/core/functions/functionCheckHaveMaxCyclomaticComplexity.test.ts +8 -0
- package/src/core/functions/functionCheckHaveMaxCyclomaticComplexity.ts +20 -0
- package/src/core/functions/functionCheckHaveMinMaintainabilityIndex.test.ts +8 -0
- package/src/core/functions/functionCheckHaveMinMaintainabilityIndex.ts +20 -0
- package/src/core/functions/functionCheckHaveModifier.test.ts +30 -0
- package/src/core/functions/functionCheckHaveModifier.ts +18 -0
- package/src/core/functions/functionCheckHaveNameMatchingFileName.test.ts +30 -0
- package/src/core/functions/functionCheckHaveNameMatchingFileName.ts +16 -0
- package/src/core/functions/functionCheckMatchNamePattern.test.ts +30 -0
- package/src/core/functions/functionCheckMatchNamePattern.ts +18 -0
- package/src/core/functions/locateFunctions.test.ts +16 -0
- package/src/core/functions/locateFunctions.ts +47 -0
- package/src/core/functions/types.ts +13 -0
- package/src/core/layers/checkLayeredArchitecture.test.ts +23 -0
- package/src/core/layers/checkLayeredArchitecture.ts +15 -0
- package/src/core/layers/createLayeredArchitecture.test.ts +13 -0
- package/src/core/layers/createLayeredArchitecture.ts +15 -0
- package/src/core/layers/getLayerDependencies.ts +45 -0
- package/src/core/layers/layer.test.ts +12 -0
- package/src/core/layers/layer.ts +10 -0
- package/src/core/layers/layerShouldNotBeAccessedByAnyLayer.test.ts +14 -0
- package/src/core/layers/layerShouldNotBeAccessedByAnyLayer.ts +40 -0
- package/src/core/layers/layerShouldOnlyBeAccessedBy.test.ts +15 -0
- package/src/core/layers/layerShouldOnlyBeAccessedBy.ts +48 -0
- package/src/core/layers/types.ts +9 -0
- package/src/core/metrics/calculateCyclomaticComplexity.test.ts +23 -0
- package/src/core/metrics/calculateCyclomaticComplexity.ts +36 -0
- package/src/core/metrics/calculateMaintainabilityIndex.test.ts +38 -0
- package/src/core/metrics/calculateMaintainabilityIndex.ts +47 -0
- package/src/core/project/parseProject.test.ts +19 -0
- package/src/core/project/parseProject.ts +216 -0
- package/src/core/properties/locateProperties.test.ts +19 -0
- package/src/core/properties/locateProperties.ts +41 -0
- package/src/core/properties/propertyCheckBeReadonly.test.ts +32 -0
- package/src/core/properties/propertyCheckBeReadonly.ts +27 -0
- package/src/core/properties/types.ts +12 -0
- package/src/core/shared/sharedCheckHaveMaxCyclomaticComplexity.test.ts +30 -0
- package/src/core/shared/sharedCheckHaveMaxCyclomaticComplexity.ts +23 -0
- package/src/core/shared/sharedCheckHaveMinMaintainabilityIndex.test.ts +30 -0
- package/src/core/shared/sharedCheckHaveMinMaintainabilityIndex.ts +23 -0
- package/src/core/shared/sharedCheckHaveModifier.test.ts +31 -0
- package/src/core/shared/sharedCheckHaveModifier.ts +51 -0
- package/src/core/shared/sharedCheckHaveNameMatchingFileName.test.ts +17 -0
- package/src/core/shared/sharedCheckHaveNameMatchingFileName.ts +36 -0
- package/src/core/shared/sharedCheckMatchNamePattern.test.ts +29 -0
- package/src/core/shared/sharedCheckMatchNamePattern.ts +22 -0
- package/src/core/slices/locateSlices.test.ts +22 -0
- package/src/core/slices/locateSlices.ts +35 -0
- package/src/core/slices/sliceCheckBeFreeOfCycles.test.ts +26 -0
- package/src/core/slices/sliceCheckBeFreeOfCycles.ts +91 -0
- package/src/core/slices/sliceCheckHaveMaxDistanceFromMainSequence.test.ts +27 -0
- package/src/core/slices/sliceCheckHaveMaxDistanceFromMainSequence.ts +110 -0
- package/src/core/slices/types.ts +9 -0
- package/src/core/testUtils.ts +61 -0
- package/src/core/types.ts +15 -0
- package/src/core/utils/ruleBuilder.test.ts +24 -0
- package/src/core/utils/ruleBuilder.ts +28 -0
- package/src/index.ts +34 -8
- package/src/matchers/index.ts +269 -51
- package/test/architecture.test.ts +109 -16
- package/tsconfig.json +2 -1
- package/vite.config.ts +2 -2
- package/dist/src/core/ClassLocator.d.ts +0 -20
- package/dist/src/core/FileLocator.d.ts +0 -15
- package/dist/src/core/FunctionLocator.d.ts +0 -15
- package/dist/src/core/LayerLocator.d.ts +0 -23
- package/dist/src/core/Project.d.ts +0 -20
- package/dist/src/core/PropertyLocator.d.ts +0 -12
- package/dist/src/core/SliceLocator.d.ts +0 -10
- package/src/core/ClassLocator.ts +0 -226
- package/src/core/FileLocator.ts +0 -168
- package/src/core/FunctionLocator.ts +0 -105
- package/src/core/LayerLocator.ts +0 -119
- package/src/core/Project.ts +0 -171
- package/src/core/PropertyLocator.ts +0 -50
- package/src/core/SliceLocator.ts +0 -92
package/src/core/Project.ts
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import { FileLocator, FileQueryOptions } from './FileLocator';
|
|
4
|
-
import { ClassLocator, ClassQueryOptions } from './ClassLocator';
|
|
5
|
-
import { LayeredArchitectureBuilder } from './LayerLocator';
|
|
6
|
-
import { FunctionLocator, FunctionQueryOptions } from './FunctionLocator';
|
|
7
|
-
import { PropertyLocator, PropertyQueryOptions } from './PropertyLocator';
|
|
8
|
-
import { SliceLocator } from './SliceLocator';
|
|
9
|
-
|
|
10
|
-
export class Project {
|
|
11
|
-
private program: ts.Program;
|
|
12
|
-
private typeChecker: ts.TypeChecker;
|
|
13
|
-
|
|
14
|
-
constructor(options: { tsConfigFilePath?: string } = {}) {
|
|
15
|
-
let compilerOptions: ts.CompilerOptions = {};
|
|
16
|
-
const configPath = options.tsConfigFilePath || ts.findConfigFile(
|
|
17
|
-
process.cwd(),
|
|
18
|
-
ts.sys.fileExists,
|
|
19
|
-
'tsconfig.json'
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
if (configPath) {
|
|
23
|
-
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
24
|
-
const parsedCommandLine = ts.parseJsonConfigFileContent(
|
|
25
|
-
configFile.config,
|
|
26
|
-
ts.sys,
|
|
27
|
-
path.dirname(configPath),
|
|
28
|
-
undefined,
|
|
29
|
-
configPath,
|
|
30
|
-
undefined,
|
|
31
|
-
[
|
|
32
|
-
{ extension: '.vue', isMixedContent: true, scriptKind: ts.ScriptKind.TS },
|
|
33
|
-
{ extension: '.svelte', isMixedContent: true, scriptKind: ts.ScriptKind.TS }
|
|
34
|
-
]
|
|
35
|
-
);
|
|
36
|
-
compilerOptions = parsedCommandLine.options;
|
|
37
|
-
|
|
38
|
-
const host = ts.createCompilerHost(compilerOptions);
|
|
39
|
-
const originalGetSourceFile = host.getSourceFile;
|
|
40
|
-
|
|
41
|
-
let vueCompiler: any;
|
|
42
|
-
try {
|
|
43
|
-
vueCompiler = require('@vue/compiler-sfc');
|
|
44
|
-
} catch (e) {
|
|
45
|
-
// Not a Vue project
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
host.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
|
|
49
|
-
if (fileName.endsWith('.vue')) {
|
|
50
|
-
const content = ts.sys.readFile(fileName);
|
|
51
|
-
if (content) {
|
|
52
|
-
let scriptContent = '';
|
|
53
|
-
if (vueCompiler) {
|
|
54
|
-
const parsed = vueCompiler.parse(content);
|
|
55
|
-
const script = parsed.descriptor.script;
|
|
56
|
-
const scriptSetup = parsed.descriptor.scriptSetup;
|
|
57
|
-
if (script) scriptContent += script.content + '\n';
|
|
58
|
-
if (scriptSetup) scriptContent += scriptSetup.content + '\n';
|
|
59
|
-
} else {
|
|
60
|
-
// Fallback for Svelte or if compiler-sfc is missing (fragile but works for simple cases)
|
|
61
|
-
const match = content.match(/<script[^>]*>(.*?)<\/script>/s);
|
|
62
|
-
if (match) scriptContent = match[1];
|
|
63
|
-
}
|
|
64
|
-
return ts.createSourceFile(fileName, scriptContent, languageVersion, true, ts.ScriptKind.TS);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (fileName.endsWith('.svelte')) {
|
|
69
|
-
const content = ts.sys.readFile(fileName);
|
|
70
|
-
if (content) {
|
|
71
|
-
let scriptContent = '';
|
|
72
|
-
const match = content.match(/<script[^>]*>(.*?)<\/script>/s);
|
|
73
|
-
if (match) scriptContent = match[1];
|
|
74
|
-
return ts.createSourceFile(fileName, scriptContent, languageVersion, true, ts.ScriptKind.TS);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return originalGetSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile);
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
this.program = ts.createProgram({
|
|
82
|
-
rootNames: parsedCommandLine.fileNames,
|
|
83
|
-
options: compilerOptions,
|
|
84
|
-
host: host
|
|
85
|
-
});
|
|
86
|
-
} else {
|
|
87
|
-
throw new Error("Could not find tsconfig.json");
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
this.typeChecker = this.program.getTypeChecker();
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
getFiles(options?: FileQueryOptions) {
|
|
94
|
-
const sourceFiles = this.program.getSourceFiles().filter(
|
|
95
|
-
sf => !sf.isDeclarationFile && !sf.fileName.includes('node_modules')
|
|
96
|
-
);
|
|
97
|
-
return new FileLocator(sourceFiles, this.program, options);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
getClasses(options?: ClassQueryOptions) {
|
|
101
|
-
const sourceFiles = this.program.getSourceFiles().filter(
|
|
102
|
-
sf => !sf.isDeclarationFile && !sf.fileName.includes('node_modules')
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
const allClasses: ts.ClassDeclaration[] = [];
|
|
106
|
-
for (const sf of sourceFiles) {
|
|
107
|
-
const visit = (node: ts.Node) => {
|
|
108
|
-
if (ts.isClassDeclaration(node)) {
|
|
109
|
-
allClasses.push(node);
|
|
110
|
-
}
|
|
111
|
-
ts.forEachChild(node, visit);
|
|
112
|
-
};
|
|
113
|
-
visit(sf);
|
|
114
|
-
}
|
|
115
|
-
return new ClassLocator(allClasses, this.program, options);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
layeredArchitecture() {
|
|
119
|
-
const sourceFiles = this.program.getSourceFiles().filter(
|
|
120
|
-
sf => !sf.isDeclarationFile && !sf.fileName.includes('node_modules')
|
|
121
|
-
);
|
|
122
|
-
return new LayeredArchitectureBuilder(sourceFiles, this.program);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
getFunctions(options?: FunctionQueryOptions) {
|
|
126
|
-
const sourceFiles = this.program.getSourceFiles().filter(
|
|
127
|
-
sf => !sf.isDeclarationFile && !sf.fileName.includes('node_modules')
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
const allFunctions: ts.FunctionLikeDeclaration[] = [];
|
|
131
|
-
for (const sf of sourceFiles) {
|
|
132
|
-
const visit = (node: ts.Node) => {
|
|
133
|
-
if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node) || ts.isArrowFunction(node)) {
|
|
134
|
-
allFunctions.push(node);
|
|
135
|
-
}
|
|
136
|
-
ts.forEachChild(node, visit);
|
|
137
|
-
};
|
|
138
|
-
visit(sf);
|
|
139
|
-
}
|
|
140
|
-
return new FunctionLocator(allFunctions, this.program, options);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
getProperties(options?: PropertyQueryOptions) {
|
|
144
|
-
const sourceFiles = this.program.getSourceFiles().filter(
|
|
145
|
-
sf => !sf.isDeclarationFile && !sf.fileName.includes('node_modules')
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
const allProperties: ts.PropertyDeclaration[] = [];
|
|
149
|
-
for (const sf of sourceFiles) {
|
|
150
|
-
const visit = (node: ts.Node) => {
|
|
151
|
-
if (ts.isPropertyDeclaration(node)) {
|
|
152
|
-
allProperties.push(node);
|
|
153
|
-
}
|
|
154
|
-
ts.forEachChild(node, visit);
|
|
155
|
-
};
|
|
156
|
-
visit(sf);
|
|
157
|
-
}
|
|
158
|
-
return new PropertyLocator(allProperties, this.program, options);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
getSlices(pattern: string) {
|
|
162
|
-
const sourceFiles = this.program.getSourceFiles().filter(
|
|
163
|
-
sf => !sf.isDeclarationFile && !sf.fileName.includes('node_modules')
|
|
164
|
-
);
|
|
165
|
-
return new SliceLocator(sourceFiles, this.program, pattern);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export function parseProject(tsConfigFilePath?: string): Project {
|
|
170
|
-
return new Project({ tsConfigFilePath });
|
|
171
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript';
|
|
2
|
-
import { RuleResult } from './types';
|
|
3
|
-
|
|
4
|
-
export interface PropertyQueryOptions {
|
|
5
|
-
inFolder?: string;
|
|
6
|
-
matchNamePattern?: string | RegExp;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export class PropertyLocator {
|
|
10
|
-
public readonly properties: ts.PropertyDeclaration[];
|
|
11
|
-
|
|
12
|
-
constructor(properties: ts.PropertyDeclaration[], private program: ts.Program, options?: PropertyQueryOptions) {
|
|
13
|
-
let filtered = properties;
|
|
14
|
-
|
|
15
|
-
if (options?.inFolder) {
|
|
16
|
-
filtered = filtered.filter((p) => {
|
|
17
|
-
const sourceFile = p.getSourceFile();
|
|
18
|
-
return sourceFile.fileName.includes(`/${options.inFolder}/`) || sourceFile.fileName.includes(`\\${options.inFolder}\\`);
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (options?.matchNamePattern) {
|
|
23
|
-
const regex = typeof options.matchNamePattern === 'string' ? new RegExp(options.matchNamePattern) : options.matchNamePattern;
|
|
24
|
-
filtered = filtered.filter((p) => {
|
|
25
|
-
return ts.isIdentifier(p.name) && regex.test(p.name.text);
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
this.properties = filtered;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
checkBeReadonly(isNot: boolean): RuleResult {
|
|
33
|
-
const violations: string[] = [];
|
|
34
|
-
for (const p of this.properties) {
|
|
35
|
-
const name = ts.isIdentifier(p.name) ? p.name.text : 'Anonymous Property';
|
|
36
|
-
const modifiers = ts.canHaveModifiers(p) ? ts.getModifiers(p) : undefined;
|
|
37
|
-
const matches = modifiers && modifiers.some((m: ts.Modifier) => m.kind === ts.SyntaxKind.ReadonlyKeyword);
|
|
38
|
-
|
|
39
|
-
if (isNot && matches) {
|
|
40
|
-
violations.push(`Property ${name} is readonly, but it shouldn't be.`);
|
|
41
|
-
} else if (!isNot && !matches) {
|
|
42
|
-
violations.push(`Property ${name} is not readonly, but it should be.`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return {
|
|
46
|
-
pass: violations.length === 0,
|
|
47
|
-
message: () => violations.join('\n'),
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
}
|
package/src/core/SliceLocator.ts
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript';
|
|
2
|
-
import { RuleResult } from './types';
|
|
3
|
-
|
|
4
|
-
export class SliceLocator {
|
|
5
|
-
private slicePattern: RegExp;
|
|
6
|
-
private sliceIds: Set<string> = new Set();
|
|
7
|
-
private sliceFiles: Map<string, ts.SourceFile[]> = new Map();
|
|
8
|
-
|
|
9
|
-
constructor(sourceFiles: ts.SourceFile[], private program: ts.Program, pattern: string) {
|
|
10
|
-
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
|
|
11
|
-
const regexStr = escaped.replace(/\*/g, '([^/\\\\]+)');
|
|
12
|
-
this.slicePattern = new RegExp(regexStr);
|
|
13
|
-
|
|
14
|
-
for (const sf of sourceFiles) {
|
|
15
|
-
const match = sf.fileName.match(this.slicePattern);
|
|
16
|
-
if (match && match[1]) {
|
|
17
|
-
const sliceId = match[1];
|
|
18
|
-
this.sliceIds.add(sliceId);
|
|
19
|
-
if (!this.sliceFiles.has(sliceId)) {
|
|
20
|
-
this.sliceFiles.set(sliceId, []);
|
|
21
|
-
}
|
|
22
|
-
this.sliceFiles.get(sliceId)!.push(sf);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
checkBeFreeOfCycles(isNot: boolean): RuleResult {
|
|
28
|
-
const graph: Map<string, Set<string>> = new Map();
|
|
29
|
-
for (const slice of this.sliceIds) {
|
|
30
|
-
graph.set(slice, new Set());
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
for (const [sliceId, files] of this.sliceFiles.entries()) {
|
|
34
|
-
for (const sf of files) {
|
|
35
|
-
ts.forEachChild(sf, (node) => {
|
|
36
|
-
if (ts.isImportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) {
|
|
37
|
-
const importPath = node.moduleSpecifier.text;
|
|
38
|
-
const resolved = ts.resolveModuleName(importPath, sf.fileName, this.program.getCompilerOptions(), ts.sys);
|
|
39
|
-
if (resolved.resolvedModule && resolved.resolvedModule.resolvedFileName) {
|
|
40
|
-
const targetMatch = resolved.resolvedModule.resolvedFileName.match(this.slicePattern);
|
|
41
|
-
if (targetMatch && targetMatch[1]) {
|
|
42
|
-
const targetSlice = targetMatch[1];
|
|
43
|
-
if (targetSlice !== sliceId && this.sliceIds.has(targetSlice)) {
|
|
44
|
-
graph.get(sliceId)!.add(targetSlice);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const visited = new Set<string>();
|
|
54
|
-
const recursionStack = new Set<string>();
|
|
55
|
-
const violations: string[] = [];
|
|
56
|
-
|
|
57
|
-
const dfs = (node: string, path: string[]): boolean => {
|
|
58
|
-
visited.add(node);
|
|
59
|
-
recursionStack.add(node);
|
|
60
|
-
|
|
61
|
-
for (const neighbor of (graph.get(node) || [])) {
|
|
62
|
-
if (!visited.has(neighbor)) {
|
|
63
|
-
if (dfs(neighbor, [...path, neighbor])) return true;
|
|
64
|
-
} else if (recursionStack.has(neighbor)) {
|
|
65
|
-
violations.push(`Cycle detected between slices: ${path.join(' -> ')} -> ${neighbor}`);
|
|
66
|
-
return true;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
recursionStack.delete(node);
|
|
71
|
-
return false;
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
for (const slice of this.sliceIds) {
|
|
75
|
-
if (!visited.has(slice)) {
|
|
76
|
-
dfs(slice, [slice]);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (isNot) {
|
|
81
|
-
return {
|
|
82
|
-
pass: violations.length > 0,
|
|
83
|
-
message: () => violations.length > 0 ? '' : 'Expected cycles between slices but found none.'
|
|
84
|
-
};
|
|
85
|
-
} else {
|
|
86
|
-
return {
|
|
87
|
-
pass: violations.length === 0,
|
|
88
|
-
message: () => violations.join('\n')
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|