@iris-code/core 0.1.0
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/README.md +38 -0
- package/dist/config.d.ts +147 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +550 -0
- package/dist/config.js.map +1 -0
- package/dist/csharp/analyser.d.ts +14 -0
- package/dist/csharp/analyser.d.ts.map +1 -0
- package/dist/csharp/analyser.js +436 -0
- package/dist/csharp/analyser.js.map +1 -0
- package/dist/csharp/lexer.d.ts +29 -0
- package/dist/csharp/lexer.d.ts.map +1 -0
- package/dist/csharp/lexer.js +182 -0
- package/dist/csharp/lexer.js.map +1 -0
- package/dist/duplicates.d.ts +53 -0
- package/dist/duplicates.d.ts.map +1 -0
- package/dist/duplicates.js +491 -0
- package/dist/duplicates.js.map +1 -0
- package/dist/fileAnalyser.d.ts +4 -0
- package/dist/fileAnalyser.d.ts.map +1 -0
- package/dist/fileAnalyser.js +8 -0
- package/dist/fileAnalyser.js.map +1 -0
- package/dist/fileNaming.d.ts +68 -0
- package/dist/fileNaming.d.ts.map +1 -0
- package/dist/fileNaming.js +343 -0
- package/dist/fileNaming.js.map +1 -0
- package/dist/gate.d.ts +49 -0
- package/dist/gate.d.ts.map +1 -0
- package/dist/gate.js +242 -0
- package/dist/gate.js.map +1 -0
- package/dist/go/analyser.d.ts +5 -0
- package/dist/go/analyser.d.ts.map +1 -0
- package/dist/go/analyser.js +576 -0
- package/dist/go/analyser.js.map +1 -0
- package/dist/guards.d.ts +16 -0
- package/dist/guards.d.ts.map +1 -0
- package/dist/guards.js +355 -0
- package/dist/guards.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +110 -0
- package/dist/index.js.map +1 -0
- package/dist/languages.d.ts +46 -0
- package/dist/languages.d.ts.map +1 -0
- package/dist/languages.js +155 -0
- package/dist/languages.js.map +1 -0
- package/dist/lines.d.ts +9 -0
- package/dist/lines.d.ts.map +1 -0
- package/dist/lines.js +58 -0
- package/dist/lines.js.map +1 -0
- package/dist/python/analyser.d.ts +5 -0
- package/dist/python/analyser.d.ts.map +1 -0
- package/dist/python/analyser.js +630 -0
- package/dist/python/analyser.js.map +1 -0
- package/dist/qualitySignals.d.ts +30 -0
- package/dist/qualitySignals.d.ts.map +1 -0
- package/dist/qualitySignals.js +101 -0
- package/dist/qualitySignals.js.map +1 -0
- package/dist/ruby/analyser.d.ts +5 -0
- package/dist/ruby/analyser.d.ts.map +1 -0
- package/dist/ruby/analyser.js +450 -0
- package/dist/ruby/analyser.js.map +1 -0
- package/dist/scoring.d.ts +4 -0
- package/dist/scoring.d.ts.map +1 -0
- package/dist/scoring.js +37 -0
- package/dist/scoring.js.map +1 -0
- package/dist/secrets.d.ts +5 -0
- package/dist/secrets.d.ts.map +1 -0
- package/dist/secrets.js +245 -0
- package/dist/secrets.js.map +1 -0
- package/dist/securityContext.d.ts +2 -0
- package/dist/securityContext.d.ts.map +1 -0
- package/dist/securityContext.js +16 -0
- package/dist/securityContext.js.map +1 -0
- package/dist/sfc.d.ts +32 -0
- package/dist/sfc.d.ts.map +1 -0
- package/dist/sfc.js +228 -0
- package/dist/sfc.js.map +1 -0
- package/dist/slop.d.ts +37 -0
- package/dist/slop.d.ts.map +1 -0
- package/dist/slop.js +81 -0
- package/dist/slop.js.map +1 -0
- package/dist/suppressions.d.ts +19 -0
- package/dist/suppressions.d.ts.map +1 -0
- package/dist/suppressions.js +152 -0
- package/dist/suppressions.js.map +1 -0
- package/dist/ts/analyser.d.ts +4 -0
- package/dist/ts/analyser.d.ts.map +1 -0
- package/dist/ts/analyser.js +769 -0
- package/dist/ts/analyser.js.map +1 -0
- package/dist/types.d.ts +139 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +46 -0
- package/dist/types.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DUPLICATE_MAX_BLOCKS = exports.DUPLICATE_MAX_LINE_LENGTH = exports.DUPLICATE_MAX_FILE_LINES = void 0;
|
|
4
|
+
exports.tokeniseNormalised = tokeniseNormalised;
|
|
5
|
+
exports.stripImports = stripImports;
|
|
6
|
+
exports.detectDuplicates = detectDuplicates;
|
|
7
|
+
exports.duplicateBlockToFindings = duplicateBlockToFindings;
|
|
8
|
+
const guards_1 = require("./guards");
|
|
9
|
+
const sfc_1 = require("./sfc");
|
|
10
|
+
/** Files above this line count are excluded from duplicate comparison */
|
|
11
|
+
exports.DUPLICATE_MAX_FILE_LINES = 5000;
|
|
12
|
+
/** A single line longer than this marks the file as generated/minified and excludes it */
|
|
13
|
+
exports.DUPLICATE_MAX_LINE_LENGTH = 500;
|
|
14
|
+
/** Hard cap on reported blocks per scan (longest first) so boilerplate-heavy repos stay usable */
|
|
15
|
+
exports.DUPLICATE_MAX_BLOCKS = 500;
|
|
16
|
+
/** Cap on identical-window occurrences considered per hash group (boilerplate guard) */
|
|
17
|
+
const MAX_GROUP_OCCURRENCES = 25;
|
|
18
|
+
// Union of keywords across the supported languages. Keeping keywords
|
|
19
|
+
// verbatim stops `return x` from matching `delete x` once identifiers collapse.
|
|
20
|
+
const KEYWORDS = new Set([
|
|
21
|
+
// JS/TS
|
|
22
|
+
'abstract', 'any', 'as', 'async', 'await', 'boolean', 'break', 'case', 'catch', 'class',
|
|
23
|
+
'const', 'continue', 'debugger', 'declare', 'default', 'delete', 'do', 'else', 'enum',
|
|
24
|
+
'export', 'extends', 'false', 'finally', 'for', 'from', 'function', 'get', 'if',
|
|
25
|
+
'implements', 'import', 'in', 'instanceof', 'interface', 'is', 'keyof', 'let', 'namespace',
|
|
26
|
+
'new', 'null', 'number', 'object', 'of', 'private', 'protected', 'public', 'readonly',
|
|
27
|
+
'return', 'set', 'static', 'string', 'super', 'switch', 'this', 'throw', 'true', 'try',
|
|
28
|
+
'type', 'typeof', 'undefined', 'unknown', 'var', 'void', 'while', 'with', 'yield',
|
|
29
|
+
// Go
|
|
30
|
+
'chan', 'defer', 'fallthrough', 'func', 'go', 'goto', 'map', 'package', 'range', 'select', 'struct',
|
|
31
|
+
// Python
|
|
32
|
+
'and', 'assert', 'def', 'del', 'elif', 'except', 'global', 'lambda', 'nonlocal', 'not',
|
|
33
|
+
'or', 'pass', 'raise', 'None', 'True', 'False',
|
|
34
|
+
// Ruby
|
|
35
|
+
'alias', 'begin', 'defined', 'elsif', 'ensure', 'module', 'redo', 'rescue',
|
|
36
|
+
'retry', 'self', 'then', 'undef', 'unless', 'until', 'when', 'END', 'BEGIN', 'nil',
|
|
37
|
+
]);
|
|
38
|
+
function isIdentStart(ch) {
|
|
39
|
+
return /[A-Za-z_$]/.test(ch);
|
|
40
|
+
}
|
|
41
|
+
function isIdentPart(ch) {
|
|
42
|
+
return /[\w$]/.test(ch);
|
|
43
|
+
}
|
|
44
|
+
/** Lex source into normalised tokens with original line numbers. Never throws. */
|
|
45
|
+
function tokeniseNormalised(source, filePath) {
|
|
46
|
+
const language = (0, guards_1.detectLanguage)(filePath);
|
|
47
|
+
const isPython = language === 'python';
|
|
48
|
+
const isRuby = language === 'ruby';
|
|
49
|
+
const tokens = [];
|
|
50
|
+
let line = 1;
|
|
51
|
+
let i = 0;
|
|
52
|
+
const countLines = (text) => {
|
|
53
|
+
for (const ch of text) {
|
|
54
|
+
if (ch === '\n')
|
|
55
|
+
line++;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
while (i < source.length) {
|
|
59
|
+
const ch = source[i];
|
|
60
|
+
if (ch === '\n') {
|
|
61
|
+
line++;
|
|
62
|
+
i++;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (ch === ' ' || ch === '\t' || ch === '\r') {
|
|
66
|
+
i++;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
// Comments
|
|
70
|
+
if (!isPython && ch === '/' && source[i + 1] === '/') {
|
|
71
|
+
while (i < source.length && source[i] !== '\n')
|
|
72
|
+
i++;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (!isPython && ch === '/' && source[i + 1] === '*') {
|
|
76
|
+
const end = source.indexOf('*/', i + 2);
|
|
77
|
+
const stop = end === -1 ? source.length : end + 2;
|
|
78
|
+
countLines(source.slice(i, stop));
|
|
79
|
+
i = stop;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if ((isPython || isRuby) && ch === '#') {
|
|
83
|
+
while (i < source.length && source[i] !== '\n')
|
|
84
|
+
i++;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
// Python triple-quoted strings
|
|
88
|
+
if (isPython && (source.startsWith('"""', i) || source.startsWith("'''", i))) {
|
|
89
|
+
const quote = source.slice(i, i + 3);
|
|
90
|
+
const startLine = line;
|
|
91
|
+
const end = source.indexOf(quote, i + 3);
|
|
92
|
+
const stop = end === -1 ? source.length : end + 3;
|
|
93
|
+
countLines(source.slice(i, stop));
|
|
94
|
+
tokens.push({ norm: 'STR', line: startLine });
|
|
95
|
+
i = stop;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
// Strings
|
|
99
|
+
if (ch === '"' || ch === "'" || ch === '`') {
|
|
100
|
+
const startLine = line;
|
|
101
|
+
i++;
|
|
102
|
+
while (i < source.length) {
|
|
103
|
+
const current = source[i];
|
|
104
|
+
if (current === '\\') {
|
|
105
|
+
if (source[i + 1] === '\n')
|
|
106
|
+
line++;
|
|
107
|
+
i += 2;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (current === '\n')
|
|
111
|
+
line++;
|
|
112
|
+
i++;
|
|
113
|
+
if (current === ch)
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
tokens.push({ norm: 'STR', line: startLine });
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
// Numbers (covers 0x1f, 1_000, 1.5e3 loosely)
|
|
120
|
+
if (/[0-9]/.test(ch)) {
|
|
121
|
+
while (i < source.length && /[\w.]/.test(source[i]))
|
|
122
|
+
i++;
|
|
123
|
+
tokens.push({ norm: 'NUM', line });
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
// Identifiers and keywords
|
|
127
|
+
if (isIdentStart(ch)) {
|
|
128
|
+
const start = i;
|
|
129
|
+
while (i < source.length && isIdentPart(source[i]))
|
|
130
|
+
i++;
|
|
131
|
+
const word = source.slice(start, i);
|
|
132
|
+
tokens.push({ norm: KEYWORDS.has(word) ? word : 'ID', line });
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
// Punctuation / operators: one char per token — consistent, so runs still match
|
|
136
|
+
tokens.push({ norm: ch, line });
|
|
137
|
+
i++;
|
|
138
|
+
}
|
|
139
|
+
return tokens;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Blanks import/re-export statements so they never participate in matching
|
|
143
|
+
* (newlines are preserved, so reported line numbers stay exact). Import
|
|
144
|
+
* headers are structural boilerplate - two Next.js pages importing the same
|
|
145
|
+
* twenty UI components are not copy-paste debt, and established duplication
|
|
146
|
+
* engines (e.g. SonarQube's CPD) exclude imports for the same reason.
|
|
147
|
+
*/
|
|
148
|
+
function stripImports(source, filePath) {
|
|
149
|
+
const language = (0, guards_1.detectLanguage)(filePath);
|
|
150
|
+
const lines = source.split('\n');
|
|
151
|
+
const blanked = new Array(lines.length).fill(false);
|
|
152
|
+
if (language === 'python') {
|
|
153
|
+
let i = 0;
|
|
154
|
+
while (i < lines.length) {
|
|
155
|
+
const trimmed = lines[i].trim();
|
|
156
|
+
if (!/^(import|from)\s/.test(trimmed)) {
|
|
157
|
+
i++;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
// Multi-line: parenthesised name list or explicit backslash continuation
|
|
161
|
+
let open = 0;
|
|
162
|
+
let j = i;
|
|
163
|
+
for (; j < lines.length && j - i < 40; j++) {
|
|
164
|
+
blanked[j] = true;
|
|
165
|
+
for (const ch of lines[j]) {
|
|
166
|
+
if (ch === '(')
|
|
167
|
+
open++;
|
|
168
|
+
else if (ch === ')')
|
|
169
|
+
open = Math.max(0, open - 1);
|
|
170
|
+
}
|
|
171
|
+
if (open === 0 && !lines[j].trimEnd().endsWith('\\'))
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
i = j + 1;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
else if (language === 'ruby') {
|
|
178
|
+
for (let i = 0; i < lines.length; i++) {
|
|
179
|
+
if (/^\s*(?:require|require_relative|load|autoload)\b/.test(lines[i]))
|
|
180
|
+
blanked[i] = true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else if (language === 'go') {
|
|
184
|
+
let i = 0;
|
|
185
|
+
while (i < lines.length) {
|
|
186
|
+
const trimmed = lines[i].trim();
|
|
187
|
+
if (/^import\s*\(/.test(trimmed)) {
|
|
188
|
+
let j = i;
|
|
189
|
+
for (; j < lines.length && j - i < 200; j++) {
|
|
190
|
+
blanked[j] = true;
|
|
191
|
+
if (j > i && lines[j].trim().startsWith(')'))
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
i = j + 1;
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
if (/^import\s+/.test(trimmed))
|
|
198
|
+
blanked[i] = true;
|
|
199
|
+
i++;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
// JS/TS: `import ...` statements, `export ... from '...'` re-exports, and
|
|
204
|
+
// CommonJS `const x = require('y')` headers (Node convention). A statement
|
|
205
|
+
// terminates at a module-specifier string or a semicolon; if it never
|
|
206
|
+
// terminates (e.g. a plain `export {` list), leave it untouched.
|
|
207
|
+
const isTerminated = (statement) => /['"]\s*\)?\s*;?\s*$/.test(statement) || /;\s*$/.test(statement);
|
|
208
|
+
const REQUIRE_RE = /^(const|let|var)\s+[\w$]+\s*=\s*require\s*\(|^(const|let|var)\s*\{[^}]*\}\s*=\s*require\s*\(/;
|
|
209
|
+
// A `const {` opener MIGHT be a multi-line destructured require; consume
|
|
210
|
+
// the statement and decide at the end - non-requires are left untouched.
|
|
211
|
+
const MAYBE_REQUIRE_RE = /^(const|let|var)\s*\{[^}]*$/;
|
|
212
|
+
let i = 0;
|
|
213
|
+
while (i < lines.length) {
|
|
214
|
+
const trimmed = lines[i].trim();
|
|
215
|
+
const startsImport = /^import\b/.test(trimmed) || REQUIRE_RE.test(trimmed);
|
|
216
|
+
const startsReExport = /^export\s+(type\s+)?[{*]/.test(trimmed);
|
|
217
|
+
const maybeRequire = MAYBE_REQUIRE_RE.test(trimmed);
|
|
218
|
+
if (!startsImport && !startsReExport && !maybeRequire) {
|
|
219
|
+
i++;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
let statement = trimmed;
|
|
223
|
+
let j = i;
|
|
224
|
+
while (j < lines.length - 1 && !isTerminated(statement) && j - i < 40) {
|
|
225
|
+
j++;
|
|
226
|
+
statement += ' ' + lines[j].trim();
|
|
227
|
+
}
|
|
228
|
+
const isImportLike = startsImport ||
|
|
229
|
+
(startsReExport && /\bfrom\s+['"]/.test(statement)) ||
|
|
230
|
+
(maybeRequire && /\}\s*=\s*require\s*\(\s*['"][^'"]*['"]\s*\)/.test(statement));
|
|
231
|
+
if (isTerminated(statement) && isImportLike) {
|
|
232
|
+
for (let k = i; k <= j; k++)
|
|
233
|
+
blanked[k] = true;
|
|
234
|
+
i = j + 1;
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
i++;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return lines.map((line, index) => (blanked[index] ? '' : line)).join('\n');
|
|
241
|
+
}
|
|
242
|
+
// React code in plain .js files (CRA, older Next.js) carries JSX without the
|
|
243
|
+
// .jsx extension - closing component tags are unambiguous there (no generics
|
|
244
|
+
// in .js), so a handful of them marks the file as markup.
|
|
245
|
+
const JS_EXT_RE = /\.(js|mjs|cjs)$/i;
|
|
246
|
+
const JSX_CLOSING_TAG_RE = /<\/[A-Za-z]/g;
|
|
247
|
+
function isMarkupFile(filePath, content) {
|
|
248
|
+
if (/\.(jsx|tsx)$/i.test(filePath))
|
|
249
|
+
return true;
|
|
250
|
+
if (!JS_EXT_RE.test(filePath))
|
|
251
|
+
return false;
|
|
252
|
+
const matches = content.match(JSX_CLOSING_TAG_RE);
|
|
253
|
+
return (matches?.length ?? 0) >= 3;
|
|
254
|
+
}
|
|
255
|
+
function isComparableFile(content) {
|
|
256
|
+
let lines = 1;
|
|
257
|
+
let lineLength = 0;
|
|
258
|
+
for (const ch of content) {
|
|
259
|
+
if (ch === '\n') {
|
|
260
|
+
lines++;
|
|
261
|
+
lineLength = 0;
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
lineLength++;
|
|
265
|
+
if (lineLength > exports.DUPLICATE_MAX_LINE_LENGTH)
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return lines <= exports.DUPLICATE_MAX_FILE_LINES;
|
|
270
|
+
}
|
|
271
|
+
function detectDuplicates(files, minTokens = 40) {
|
|
272
|
+
const windowSize = Math.max(10, Math.floor(minTokens));
|
|
273
|
+
const skippedFiles = [];
|
|
274
|
+
const comparable = [];
|
|
275
|
+
for (const file of files) {
|
|
276
|
+
if (isComparableFile(file.content)) {
|
|
277
|
+
const prepared = (0, sfc_1.prepareSourceForAnalysis)(file.content, file.path);
|
|
278
|
+
comparable.push({ path: file.path, content: prepared.source });
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
skippedFiles.push(file.path);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
let streams;
|
|
285
|
+
try {
|
|
286
|
+
streams = comparable.map(file => tokeniseNormalised(stripImports(file.content, file.path), file.path));
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
return { blocks: [], skippedFiles };
|
|
290
|
+
}
|
|
291
|
+
const markupPaths = new Set(comparable.filter(file => isMarkupFile(file.path, file.content)).map(file => file.path));
|
|
292
|
+
// Intern normalised token text to small integers so window keys stay compact
|
|
293
|
+
const internMap = new Map();
|
|
294
|
+
const codes = streams.map(stream => stream.map(token => {
|
|
295
|
+
let code = internMap.get(token.norm);
|
|
296
|
+
if (code === undefined) {
|
|
297
|
+
code = internMap.size;
|
|
298
|
+
internMap.set(token.norm, code);
|
|
299
|
+
}
|
|
300
|
+
return code;
|
|
301
|
+
}));
|
|
302
|
+
// Uniform data literals (country lists, enum tables, config arrays) repeat
|
|
303
|
+
// a tiny token cycle - `{ ID : STR , ID : STR } ,` forever - and are data,
|
|
304
|
+
// not copy-paste debt. Such windows carry almost no distinct tokens, while
|
|
305
|
+
// real logic mixes keywords, operators, and punctuation. Windows below this
|
|
306
|
+
// diversity floor never enter matching.
|
|
307
|
+
const minDistinct = Math.max(6, Math.floor(windowSize / 5));
|
|
308
|
+
// Group identical windows by exact key — no hash collisions to verify
|
|
309
|
+
const groups = new Map();
|
|
310
|
+
for (let f = 0; f < codes.length; f++) {
|
|
311
|
+
const fileCodes = codes[f];
|
|
312
|
+
if (fileCodes.length < windowSize)
|
|
313
|
+
continue;
|
|
314
|
+
// Sliding distinct-token count over the window
|
|
315
|
+
const frequency = new Map();
|
|
316
|
+
for (let i = 0; i < windowSize; i++) {
|
|
317
|
+
frequency.set(fileCodes[i], (frequency.get(fileCodes[i]) ?? 0) + 1);
|
|
318
|
+
}
|
|
319
|
+
for (let i = 0; i + windowSize <= fileCodes.length; i++) {
|
|
320
|
+
if (i > 0) {
|
|
321
|
+
const leaving = fileCodes[i - 1];
|
|
322
|
+
const leavingCount = frequency.get(leaving) ?? 0;
|
|
323
|
+
if (leavingCount <= 1)
|
|
324
|
+
frequency.delete(leaving);
|
|
325
|
+
else
|
|
326
|
+
frequency.set(leaving, leavingCount - 1);
|
|
327
|
+
const entering = fileCodes[i + windowSize - 1];
|
|
328
|
+
frequency.set(entering, (frequency.get(entering) ?? 0) + 1);
|
|
329
|
+
}
|
|
330
|
+
if (frequency.size < minDistinct)
|
|
331
|
+
continue;
|
|
332
|
+
const key = fileCodes.slice(i, i + windowSize).join(',');
|
|
333
|
+
let occurrences = groups.get(key);
|
|
334
|
+
if (!occurrences) {
|
|
335
|
+
occurrences = [];
|
|
336
|
+
groups.set(key, occurrences);
|
|
337
|
+
}
|
|
338
|
+
if (occurrences.length < MAX_GROUP_OCCURRENCES) {
|
|
339
|
+
occurrences.push({ f, i });
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
// Matching window-start pairs, canonically ordered
|
|
344
|
+
const pairs = new Set();
|
|
345
|
+
const pairKey = (p, q) => `${p.f}:${p.i}|${q.f}:${q.i}`;
|
|
346
|
+
for (const occurrences of groups.values()) {
|
|
347
|
+
if (occurrences.length < 2)
|
|
348
|
+
continue;
|
|
349
|
+
for (let x = 0; x < occurrences.length; x++) {
|
|
350
|
+
for (let y = x + 1; y < occurrences.length; y++) {
|
|
351
|
+
const p = occurrences[x];
|
|
352
|
+
const q = occurrences[y];
|
|
353
|
+
// Same-file matches must not overlap themselves (repeated-token noise)
|
|
354
|
+
if (p.f === q.f && Math.abs(q.i - p.i) < windowSize)
|
|
355
|
+
continue;
|
|
356
|
+
const [first, second] = p.f < q.f || (p.f === q.f && p.i < q.i) ? [p, q] : [q, p];
|
|
357
|
+
pairs.add(pairKey(first, second));
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
// Grow each seed pair into its maximal block by direct token comparison.
|
|
362
|
+
// Seeds only come from diverse windows (the floor above), but extension is
|
|
363
|
+
// token-exact in both directions, so a low-diversity stretch in the middle
|
|
364
|
+
// of a real duplicate (a run of lines.push(...) calls, say) cannot split
|
|
365
|
+
// one block into fragments.
|
|
366
|
+
const blocks = [];
|
|
367
|
+
const emitted = new Set();
|
|
368
|
+
for (const key of pairs) {
|
|
369
|
+
const [left, right] = key.split('|');
|
|
370
|
+
const [pf, pi] = left.split(':').map(Number);
|
|
371
|
+
const [qf, qi] = right.split(':').map(Number);
|
|
372
|
+
let back = 0;
|
|
373
|
+
while (pi - back > 0 &&
|
|
374
|
+
qi - back > 0 &&
|
|
375
|
+
codes[pf][pi - back - 1] === codes[qf][qi - back - 1])
|
|
376
|
+
back++;
|
|
377
|
+
const startP = pi - back;
|
|
378
|
+
const startQ = qi - back;
|
|
379
|
+
let tokenLength = back + windowSize;
|
|
380
|
+
while (startP + tokenLength < codes[pf].length &&
|
|
381
|
+
startQ + tokenLength < codes[qf].length &&
|
|
382
|
+
codes[pf][startP + tokenLength] === codes[qf][startQ + tokenLength])
|
|
383
|
+
tokenLength++;
|
|
384
|
+
// Every seed inside the same run resolves to the same maximal block
|
|
385
|
+
const blockKey = `${pf}:${startP}|${qf}:${startQ}|${tokenLength}`;
|
|
386
|
+
if (emitted.has(blockKey))
|
|
387
|
+
continue;
|
|
388
|
+
emitted.add(blockKey);
|
|
389
|
+
// Second diversity pass over the merged block: a window anchored at a data
|
|
390
|
+
// table's opening line (`export const X = [`) sneaks past the per-window
|
|
391
|
+
// floor, but the whole block still reads as a repeated cycle. Real code of
|
|
392
|
+
// any size carries well over 12 distinct token kinds.
|
|
393
|
+
const blockDistinct = new Set(codes[pf].slice(startP, startP + tokenLength)).size;
|
|
394
|
+
if (blockDistinct < Math.min(12, Math.floor(tokenLength * 0.3)))
|
|
395
|
+
continue;
|
|
396
|
+
blocks.push({
|
|
397
|
+
tokens: tokenLength,
|
|
398
|
+
a: {
|
|
399
|
+
file: comparable[pf].path,
|
|
400
|
+
startLine: streams[pf][startP].line,
|
|
401
|
+
endLine: streams[pf][startP + tokenLength - 1].line,
|
|
402
|
+
},
|
|
403
|
+
b: {
|
|
404
|
+
file: comparable[qf].path,
|
|
405
|
+
startLine: streams[qf][startQ].line,
|
|
406
|
+
endLine: streams[qf][startQ + tokenLength - 1].line,
|
|
407
|
+
},
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
blocks.sort((x, y) => y.tokens - x.tokens ||
|
|
411
|
+
x.a.file.localeCompare(y.a.file) ||
|
|
412
|
+
x.a.startLine - y.a.startLine ||
|
|
413
|
+
x.b.file.localeCompare(y.b.file) ||
|
|
414
|
+
x.b.startLine - y.b.startLine);
|
|
415
|
+
// JSX markup is structurally repetitive - measured on real Next.js repos,
|
|
416
|
+
// small matched windows there are idiomatic template echoes, not copy-paste
|
|
417
|
+
// debt, and token composition does not separate the two (both sit near the
|
|
418
|
+
// same identifier density). Size does: require twice the evidence when both
|
|
419
|
+
// sides live in markup files (.jsx/.tsx, or .js carrying JSX).
|
|
420
|
+
const jsxMin = windowSize * 2;
|
|
421
|
+
const filtered = blocks.filter(block => !(markupPaths.has(block.a.file) && markupPaths.has(block.b.file)) || block.tokens >= jsxMin);
|
|
422
|
+
return { blocks: suppressTransitivePairs(filtered).slice(0, exports.DUPLICATE_MAX_BLOCKS), skippedFiles };
|
|
423
|
+
}
|
|
424
|
+
// A block repeated k times produces k(k-1)/2 matching pairs, and partial
|
|
425
|
+
// alignments add contained sub-pairs on top - pure noise past the first
|
|
426
|
+
// mention of each location. Keep the minimal pair set that still introduces
|
|
427
|
+
// every distinct location once (largest blocks first): a pair whose two sides
|
|
428
|
+
// both substantially overlap already-reported locations adds nothing.
|
|
429
|
+
function suppressTransitivePairs(blocks) {
|
|
430
|
+
const covered = new Map();
|
|
431
|
+
const isCovered = (loc) => {
|
|
432
|
+
const ranges = covered.get(loc.file);
|
|
433
|
+
if (!ranges)
|
|
434
|
+
return false;
|
|
435
|
+
const span = loc.endLine - loc.startLine + 1;
|
|
436
|
+
return ranges.some(([start, end]) => {
|
|
437
|
+
const overlap = Math.min(loc.endLine, end) - Math.max(loc.startLine, start) + 1;
|
|
438
|
+
return overlap >= span * 0.6;
|
|
439
|
+
});
|
|
440
|
+
};
|
|
441
|
+
const cover = (loc) => {
|
|
442
|
+
const ranges = covered.get(loc.file) ?? [];
|
|
443
|
+
ranges.push([loc.startLine, loc.endLine]);
|
|
444
|
+
covered.set(loc.file, ranges);
|
|
445
|
+
};
|
|
446
|
+
const kept = [];
|
|
447
|
+
for (const block of blocks) {
|
|
448
|
+
if (isCovered(block.a) && isCovered(block.b))
|
|
449
|
+
continue;
|
|
450
|
+
kept.push(block);
|
|
451
|
+
cover(block.a);
|
|
452
|
+
cover(block.b);
|
|
453
|
+
}
|
|
454
|
+
return kept;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Converts a detected block into per-file smell findings. A within-file block
|
|
458
|
+
* yields one finding; a cross-file block yields a primary finding on the first
|
|
459
|
+
* file and a non-primary mirror on the second, so totals never double-count.
|
|
460
|
+
*/
|
|
461
|
+
function duplicateBlockToFindings(block) {
|
|
462
|
+
const crossFile = block.a.file !== block.b.file;
|
|
463
|
+
const primary = {
|
|
464
|
+
line: block.a.startLine,
|
|
465
|
+
endLine: block.a.endLine,
|
|
466
|
+
tokens: block.tokens,
|
|
467
|
+
otherFile: block.b.file,
|
|
468
|
+
otherLine: block.b.startLine,
|
|
469
|
+
otherEndLine: block.b.endLine,
|
|
470
|
+
crossFile,
|
|
471
|
+
primary: true,
|
|
472
|
+
};
|
|
473
|
+
if (!crossFile) {
|
|
474
|
+
return [{ file: block.a.file, finding: primary }];
|
|
475
|
+
}
|
|
476
|
+
const mirror = {
|
|
477
|
+
line: block.b.startLine,
|
|
478
|
+
endLine: block.b.endLine,
|
|
479
|
+
tokens: block.tokens,
|
|
480
|
+
otherFile: block.a.file,
|
|
481
|
+
otherLine: block.a.startLine,
|
|
482
|
+
otherEndLine: block.a.endLine,
|
|
483
|
+
crossFile,
|
|
484
|
+
primary: false,
|
|
485
|
+
};
|
|
486
|
+
return [
|
|
487
|
+
{ file: block.a.file, finding: primary },
|
|
488
|
+
{ file: block.b.file, finding: mirror },
|
|
489
|
+
];
|
|
490
|
+
}
|
|
491
|
+
//# sourceMappingURL=duplicates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duplicates.js","sourceRoot":"","sources":["../src/duplicates.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Language, FileAnalysis, FunctionInfo, Warning, TypeScriptMetrics, CodeSmells, UnusedImport, LanguageAnalysis } from './types';
|
|
2
|
+
export type { Language, FileAnalysis, FunctionInfo, Warning, TypeScriptMetrics, CodeSmells, UnusedImport, LanguageAnalysis };
|
|
3
|
+
export { analyseFile } from './index';
|
|
4
|
+
//# sourceMappingURL=fileAnalyser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileAnalyser.d.ts","sourceRoot":"","sources":["../src/fileAnalyser.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,OAAO,EACP,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,gBAAgB,EACjB,MAAM,SAAS,CAAA;AAGhB,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,CAAA;AAI5H,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.analyseFile = void 0;
|
|
4
|
+
// Compat shim: delegate to the main router so parse-error guards and inline
|
|
5
|
+
// suppressions behave identically no matter which entry point is imported.
|
|
6
|
+
var index_1 = require("./index");
|
|
7
|
+
Object.defineProperty(exports, "analyseFile", { enumerable: true, get: function () { return index_1.analyseFile; } });
|
|
8
|
+
//# sourceMappingURL=fileAnalyser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileAnalyser.js","sourceRoot":"","sources":["../src/fileAnalyser.ts"],"names":[],"mappings":";;;AAcA,4EAA4E;AAC5E,2EAA2E;AAC3E,iCAAqC;AAA5B,oGAAA,WAAW,OAAA"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { FileNamingConfig, FileNamingConvention, FileNamingPolicy, IrisConfig } from './config';
|
|
2
|
+
import type { FileNamingFinding } from './types';
|
|
3
|
+
export type { FileNamingFinding } from './types';
|
|
4
|
+
export declare const FILE_NAMING_MULTI_DOT_SUFFIXES: readonly [".test", ".spec", ".stories", ".story", ".generated"];
|
|
5
|
+
export declare const FILE_NAMING_EXEMPTIONS: {
|
|
6
|
+
readonly nextReservedStems: readonly ["page", "layout", "route", "loading", "error", "global-error", "not-found", "template", "default", "middleware", "instrumentation", "opengraph-image", "sitemap", "robots", "manifest", "_app", "_document", "_error"];
|
|
7
|
+
readonly pythonReservedFiles: readonly ["__init__.py", "__main__.py", "conftest.py", "setup.py", "manage.py"];
|
|
8
|
+
readonly generatedDirectories: readonly ["vendor", "node_modules", "dist", "build", ".next", "__pycache__"];
|
|
9
|
+
readonly svelteKitRoutePrefix: "+";
|
|
10
|
+
};
|
|
11
|
+
export declare const FILE_NAMING_GLOB_MAX_LENGTH = 1024;
|
|
12
|
+
/**
|
|
13
|
+
* True when a pattern can be compiled and used. An over-long or uncompilable
|
|
14
|
+
* glob is reported by the config resolver so the user is told, rather than the
|
|
15
|
+
* pattern silently doing nothing.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isUsableFileNamingGlob(pattern: string): boolean;
|
|
18
|
+
export declare function matchesAnyFileNamingGlob(filePath: string, patterns: readonly string[]): boolean;
|
|
19
|
+
export interface ResolvedFileNamingPolicy {
|
|
20
|
+
convention: FileNamingConvention;
|
|
21
|
+
scope?: 'new-files' | 'all';
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolve one workspace-relative path. Global ignores win; matching overrides
|
|
25
|
+
* are applied in declaration order with the last match winning.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveFileNamingPolicy(relativePath: string, config: FileNamingConfig | FileNamingPolicy | undefined): ResolvedFileNamingPolicy | null;
|
|
28
|
+
/**
|
|
29
|
+
* A stem may carry DOTS, and each dot-separated segment is judged on its own.
|
|
30
|
+
* .NET names projects and partial classes that way - `Shop.Api.Tests.csproj`,
|
|
31
|
+
* `Order.Validation.cs` - and so do build files like `vite.config.ts`. Judging
|
|
32
|
+
* the whole stem at once failed every one of them, and because `suggestName`
|
|
33
|
+
* did not split on dots either, the offered fix for `Shop.Api.csproj` was
|
|
34
|
+
* `Shop.api.csproj`: a rename that breaks the solution file and every
|
|
35
|
+
* ProjectReference pointing at it.
|
|
36
|
+
*/
|
|
37
|
+
export declare function checkStem(stem: string, convention: FileNamingConvention): boolean;
|
|
38
|
+
/** Suggests per dot-separated segment, matching `checkStem`: the dots in
|
|
39
|
+
* `Shop.Api.Tests` are part of the name, not word separators. */
|
|
40
|
+
export declare function suggestName(stem: string, convention: FileNamingConvention): string;
|
|
41
|
+
export declare function isExemptPath(filePath: string): boolean;
|
|
42
|
+
export declare function checkFileNaming(relativePath: string, config: Pick<IrisConfig, 'fileNaming'> | {
|
|
43
|
+
fileNaming?: FileNamingConfig;
|
|
44
|
+
}): FileNamingFinding | null;
|
|
45
|
+
export interface DominantConvention {
|
|
46
|
+
convention: FileNamingConvention;
|
|
47
|
+
/** Non-exempt files whose stem is consistent with the winning convention. */
|
|
48
|
+
matched: number;
|
|
49
|
+
/** Non-exempt files considered. */
|
|
50
|
+
total: number;
|
|
51
|
+
/** matched / total, for the headline percentage. */
|
|
52
|
+
share: number;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Infer the naming convention a codebase already follows, so a workspace with
|
|
56
|
+
* no configured policy can be offered a one-click "adopt this" nudge.
|
|
57
|
+
*
|
|
58
|
+
* Single-word stems like `user` are consistent with snake_case, kebab-case and
|
|
59
|
+
* camelCase at once, so they cannot discriminate. The winner is chosen by the
|
|
60
|
+
* plurality of *discriminating* files (those consistent with exactly one
|
|
61
|
+
* convention, e.g. `user_row`, `user-row`, `userRow`, `UserRow`). Returns null
|
|
62
|
+
* when there is not enough discriminating signal to make an honest suggestion.
|
|
63
|
+
*/
|
|
64
|
+
export declare function detectDominantConvention(relativePaths: string[], options?: {
|
|
65
|
+
minDiscriminating?: number;
|
|
66
|
+
minShare?: number;
|
|
67
|
+
}): DominantConvention | null;
|
|
68
|
+
//# sourceMappingURL=fileNaming.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileNaming.d.ts","sourceRoot":"","sources":["../src/fileNaming.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAEhD,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAEhD,eAAO,MAAM,8BAA8B,iEAMjC,CAAA;AAEV,eAAO,MAAM,sBAAsB;;;;;CAgBzB,CAAA;AAuCV,eAAO,MAAM,2BAA2B,OAAO,CAAA;AAE/C;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAI/D;AAoDD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAM/F;AAED,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,oBAAoB,CAAA;IAChC,KAAK,CAAC,EAAE,WAAW,GAAG,KAAK,CAAA;CAC5B;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,gBAAgB,GAAG,gBAAgB,GAAG,SAAS,GACtD,wBAAwB,GAAG,IAAI,CAmBjC;AASD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,oBAAoB,GAAG,OAAO,CAGjF;AAsBD;kEACkE;AAClE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,oBAAoB,GAAG,MAAM,CAMlF;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAgCtD;AAED,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,GAAG;IAAE,UAAU,CAAC,EAAE,gBAAgB,CAAA;CAAE,GACzE,iBAAiB,GAAG,IAAI,CA0B1B;AAID,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,oBAAoB,CAAA;IAChC,6EAA6E;IAC7E,OAAO,EAAE,MAAM,CAAA;IACf,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,MAAM,EAAE,EACvB,OAAO,GAAE;IAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9D,kBAAkB,GAAG,IAAI,CA4C3B"}
|