@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.
Files changed (94) hide show
  1. package/README.md +38 -0
  2. package/dist/config.d.ts +147 -0
  3. package/dist/config.d.ts.map +1 -0
  4. package/dist/config.js +550 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/csharp/analyser.d.ts +14 -0
  7. package/dist/csharp/analyser.d.ts.map +1 -0
  8. package/dist/csharp/analyser.js +436 -0
  9. package/dist/csharp/analyser.js.map +1 -0
  10. package/dist/csharp/lexer.d.ts +29 -0
  11. package/dist/csharp/lexer.d.ts.map +1 -0
  12. package/dist/csharp/lexer.js +182 -0
  13. package/dist/csharp/lexer.js.map +1 -0
  14. package/dist/duplicates.d.ts +53 -0
  15. package/dist/duplicates.d.ts.map +1 -0
  16. package/dist/duplicates.js +491 -0
  17. package/dist/duplicates.js.map +1 -0
  18. package/dist/fileAnalyser.d.ts +4 -0
  19. package/dist/fileAnalyser.d.ts.map +1 -0
  20. package/dist/fileAnalyser.js +8 -0
  21. package/dist/fileAnalyser.js.map +1 -0
  22. package/dist/fileNaming.d.ts +68 -0
  23. package/dist/fileNaming.d.ts.map +1 -0
  24. package/dist/fileNaming.js +343 -0
  25. package/dist/fileNaming.js.map +1 -0
  26. package/dist/gate.d.ts +49 -0
  27. package/dist/gate.d.ts.map +1 -0
  28. package/dist/gate.js +242 -0
  29. package/dist/gate.js.map +1 -0
  30. package/dist/go/analyser.d.ts +5 -0
  31. package/dist/go/analyser.d.ts.map +1 -0
  32. package/dist/go/analyser.js +576 -0
  33. package/dist/go/analyser.js.map +1 -0
  34. package/dist/guards.d.ts +16 -0
  35. package/dist/guards.d.ts.map +1 -0
  36. package/dist/guards.js +355 -0
  37. package/dist/guards.js.map +1 -0
  38. package/dist/index.d.ts +22 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +110 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/languages.d.ts +46 -0
  43. package/dist/languages.d.ts.map +1 -0
  44. package/dist/languages.js +155 -0
  45. package/dist/languages.js.map +1 -0
  46. package/dist/lines.d.ts +9 -0
  47. package/dist/lines.d.ts.map +1 -0
  48. package/dist/lines.js +58 -0
  49. package/dist/lines.js.map +1 -0
  50. package/dist/python/analyser.d.ts +5 -0
  51. package/dist/python/analyser.d.ts.map +1 -0
  52. package/dist/python/analyser.js +630 -0
  53. package/dist/python/analyser.js.map +1 -0
  54. package/dist/qualitySignals.d.ts +30 -0
  55. package/dist/qualitySignals.d.ts.map +1 -0
  56. package/dist/qualitySignals.js +101 -0
  57. package/dist/qualitySignals.js.map +1 -0
  58. package/dist/ruby/analyser.d.ts +5 -0
  59. package/dist/ruby/analyser.d.ts.map +1 -0
  60. package/dist/ruby/analyser.js +450 -0
  61. package/dist/ruby/analyser.js.map +1 -0
  62. package/dist/scoring.d.ts +4 -0
  63. package/dist/scoring.d.ts.map +1 -0
  64. package/dist/scoring.js +37 -0
  65. package/dist/scoring.js.map +1 -0
  66. package/dist/secrets.d.ts +5 -0
  67. package/dist/secrets.d.ts.map +1 -0
  68. package/dist/secrets.js +245 -0
  69. package/dist/secrets.js.map +1 -0
  70. package/dist/securityContext.d.ts +2 -0
  71. package/dist/securityContext.d.ts.map +1 -0
  72. package/dist/securityContext.js +16 -0
  73. package/dist/securityContext.js.map +1 -0
  74. package/dist/sfc.d.ts +32 -0
  75. package/dist/sfc.d.ts.map +1 -0
  76. package/dist/sfc.js +228 -0
  77. package/dist/sfc.js.map +1 -0
  78. package/dist/slop.d.ts +37 -0
  79. package/dist/slop.d.ts.map +1 -0
  80. package/dist/slop.js +81 -0
  81. package/dist/slop.js.map +1 -0
  82. package/dist/suppressions.d.ts +19 -0
  83. package/dist/suppressions.d.ts.map +1 -0
  84. package/dist/suppressions.js +152 -0
  85. package/dist/suppressions.js.map +1 -0
  86. package/dist/ts/analyser.d.ts +4 -0
  87. package/dist/ts/analyser.d.ts.map +1 -0
  88. package/dist/ts/analyser.js +769 -0
  89. package/dist/ts/analyser.js.map +1 -0
  90. package/dist/types.d.ts +139 -0
  91. package/dist/types.d.ts.map +1 -0
  92. package/dist/types.js +46 -0
  93. package/dist/types.js.map +1 -0
  94. package/package.json +43 -0
@@ -0,0 +1,343 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FILE_NAMING_GLOB_MAX_LENGTH = exports.FILE_NAMING_EXEMPTIONS = exports.FILE_NAMING_MULTI_DOT_SUFFIXES = void 0;
4
+ exports.isUsableFileNamingGlob = isUsableFileNamingGlob;
5
+ exports.matchesAnyFileNamingGlob = matchesAnyFileNamingGlob;
6
+ exports.resolveFileNamingPolicy = resolveFileNamingPolicy;
7
+ exports.checkStem = checkStem;
8
+ exports.suggestName = suggestName;
9
+ exports.isExemptPath = isExemptPath;
10
+ exports.checkFileNaming = checkFileNaming;
11
+ exports.detectDominantConvention = detectDominantConvention;
12
+ exports.FILE_NAMING_MULTI_DOT_SUFFIXES = [
13
+ '.test',
14
+ '.spec',
15
+ '.stories',
16
+ '.story',
17
+ '.generated',
18
+ ];
19
+ exports.FILE_NAMING_EXEMPTIONS = {
20
+ nextReservedStems: [
21
+ 'page', 'layout', 'route', 'loading', 'error', 'global-error', 'not-found',
22
+ 'template', 'default', 'middleware', 'instrumentation', 'opengraph-image',
23
+ 'sitemap', 'robots', 'manifest', '_app', '_document', '_error',
24
+ ],
25
+ pythonReservedFiles: ['__init__.py', '__main__.py', 'conftest.py', 'setup.py', 'manage.py'],
26
+ generatedDirectories: ['vendor', 'node_modules', 'dist', 'build', '.next', '__pycache__'],
27
+ // SvelteKit routing is filename-based and every route file is `+`-prefixed:
28
+ // +page.svelte, +layout.svelte, +error.svelte, +server.ts, +page.server.ts,
29
+ // +layout.server.ts, and their .js variants. The framework resolves these by
30
+ // exact name, so they cannot be renamed - the same reason Next.js reserved
31
+ // stems and Python dunder files are exempt. They also broke the affordance,
32
+ // not just the count: `suggestName('+page')` returns '+page', so every
33
+ // SvelteKit route offered a rename to its own current name.
34
+ svelteKitRoutePrefix: '+',
35
+ };
36
+ const NEXT_RESERVED_STEMS = new Set(exports.FILE_NAMING_EXEMPTIONS.nextReservedStems);
37
+ const PYTHON_RESERVED = new Set(exports.FILE_NAMING_EXEMPTIONS.pythonReservedFiles);
38
+ const GENERATED_DIRS = new Set(exports.FILE_NAMING_EXEMPTIONS.generatedDirectories);
39
+ const GO_PLATFORM_SUFFIX = /_(?:windows|linux|darwin|freebsd|openbsd|netbsd|solaris|aix|android|ios|js|wasm|amd64|arm64|386|arm|ppc64|ppc64le|mips|mips64|mips64le|riscv64|s390x)$/;
40
+ function normalisePath(filePath) {
41
+ return filePath.replace(/\\/g, '/').replace(/^\.\//, '');
42
+ }
43
+ function basename(filePath) {
44
+ return normalisePath(filePath).split('/').pop() ?? filePath;
45
+ }
46
+ function extensionOf(fileName) {
47
+ const index = fileName.lastIndexOf('.');
48
+ return index > 0 ? fileName.slice(index) : '';
49
+ }
50
+ function stemOf(fileName) {
51
+ let stem = fileName.slice(0, fileName.length - extensionOf(fileName).length);
52
+ for (const suffix of exports.FILE_NAMING_MULTI_DOT_SUFFIXES) {
53
+ if (stem.endsWith(suffix)) {
54
+ stem = stem.slice(0, -suffix.length);
55
+ break;
56
+ }
57
+ }
58
+ if (fileName.endsWith('.go'))
59
+ stem = stem.replace(GO_PLATFORM_SUFFIX, '');
60
+ return stem;
61
+ }
62
+ // Longest accepted naming glob. These come from `.irisconfig.json`, which
63
+ // arrives with a cloned repo, so the length is untrusted. Every glob construct
64
+ // EXPANDS when compiled - a single `?` becomes a four-character class, and a
65
+ // globstar becomes an eight-character group - so a long pattern produces a far
66
+ // longer regex and can exceed the engine's own size limit.
67
+ //
68
+ // Real globs are well under 100 characters; 1024 is deliberately generous.
69
+ exports.FILE_NAMING_GLOB_MAX_LENGTH = 1024;
70
+ /**
71
+ * True when a pattern can be compiled and used. An over-long or uncompilable
72
+ * glob is reported by the config resolver so the user is told, rather than the
73
+ * pattern silently doing nothing.
74
+ */
75
+ function isUsableFileNamingGlob(pattern) {
76
+ return typeof pattern === 'string'
77
+ && pattern.length <= exports.FILE_NAMING_GLOB_MAX_LENGTH
78
+ && globToRegExp(pattern) !== null;
79
+ }
80
+ // Compiled patterns are cached because matchesAnyFileNamingGlob runs per FILE
81
+ // per pattern: a workspace scan with a handful of globs across 10k files
82
+ // otherwise recompiles the same regexes tens of thousands of times.
83
+ const globCache = new Map();
84
+ function globToRegExp(pattern) {
85
+ const cached = globCache.get(pattern);
86
+ if (cached !== undefined)
87
+ return cached;
88
+ const compiled = compileGlob(pattern);
89
+ // Bounded so a hostile config cannot grow the cache without limit.
90
+ if (globCache.size < 500)
91
+ globCache.set(pattern, compiled);
92
+ return compiled;
93
+ }
94
+ function compileGlob(pattern) {
95
+ if (typeof pattern !== 'string' || pattern.length > exports.FILE_NAMING_GLOB_MAX_LENGTH)
96
+ return null;
97
+ const normalised = normalisePath(pattern);
98
+ let result = '^';
99
+ for (let i = 0; i < normalised.length; i++) {
100
+ const char = normalised[i];
101
+ if (char === '*') {
102
+ if (normalised[i + 1] === '*') {
103
+ i++;
104
+ if (normalised[i + 1] === '/') {
105
+ i++;
106
+ result += '(?:.*/)?';
107
+ }
108
+ else {
109
+ result += '.*';
110
+ }
111
+ }
112
+ else {
113
+ result += '[^/]*';
114
+ }
115
+ }
116
+ else if (char === '?') {
117
+ result += '[^/]';
118
+ }
119
+ else {
120
+ result += char.replace(/[|\\{}()[\]^$+?.]/g, '\\$&');
121
+ }
122
+ }
123
+ try {
124
+ return new RegExp(`${result}$`);
125
+ }
126
+ catch {
127
+ // The engine refuses regexes past its own size limit ("Invalid regular
128
+ // expression"). This used to throw straight out of checkFileNaming, so a
129
+ // single long glob in a cloned repo's config aborted the whole scan with a
130
+ // stack trace and a 157 KB regex dumped to the terminal (found 2026-08-04).
131
+ return null;
132
+ }
133
+ }
134
+ function matchesAnyFileNamingGlob(filePath, patterns) {
135
+ const relative = normalisePath(filePath);
136
+ // An unusable pattern matches NOTHING, which is the fail-safe direction for
137
+ // both callers: an `ignore` entry cannot silently exempt a file from its
138
+ // convention, and an override cannot silently take over a path.
139
+ return patterns.some(pattern => globToRegExp(pattern)?.test(relative) ?? false);
140
+ }
141
+ /**
142
+ * Resolve one workspace-relative path. Global ignores win; matching overrides
143
+ * are applied in declaration order with the last match winning.
144
+ */
145
+ function resolveFileNamingPolicy(relativePath, config) {
146
+ if (!config)
147
+ return null;
148
+ const normalised = normalisePath(relativePath);
149
+ if (matchesAnyFileNamingGlob(normalised, config.ignore ?? []))
150
+ return null;
151
+ let resolved = {
152
+ convention: config.convention,
153
+ ...(config.scope ? { scope: config.scope } : {}),
154
+ };
155
+ const overrides = 'overrides' in config ? config.overrides ?? [] : [];
156
+ for (const override of overrides) {
157
+ if (!matchesAnyFileNamingGlob(normalised, override.files))
158
+ continue;
159
+ const scope = override.scope ?? resolved.scope;
160
+ resolved = {
161
+ convention: override.convention,
162
+ ...(scope ? { scope } : {}),
163
+ };
164
+ }
165
+ return resolved;
166
+ }
167
+ function checkSegment(segment, convention) {
168
+ if (convention === 'snake_case')
169
+ return /^[a-z0-9]+(?:_[a-z0-9]+)*$/.test(segment);
170
+ if (convention === 'kebab-case')
171
+ return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(segment);
172
+ if (convention === 'camelCase')
173
+ return /^[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*$/.test(segment);
174
+ return /^[A-Z][A-Za-z0-9]*$/.test(segment);
175
+ }
176
+ /**
177
+ * A stem may carry DOTS, and each dot-separated segment is judged on its own.
178
+ * .NET names projects and partial classes that way - `Shop.Api.Tests.csproj`,
179
+ * `Order.Validation.cs` - and so do build files like `vite.config.ts`. Judging
180
+ * the whole stem at once failed every one of them, and because `suggestName`
181
+ * did not split on dots either, the offered fix for `Shop.Api.csproj` was
182
+ * `Shop.api.csproj`: a rename that breaks the solution file and every
183
+ * ProjectReference pointing at it.
184
+ */
185
+ function checkStem(stem, convention) {
186
+ const segments = stem.split('.');
187
+ return segments.length > 0 && segments.every(segment => checkSegment(segment, convention));
188
+ }
189
+ function splitWords(stem) {
190
+ return stem
191
+ .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
192
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
193
+ .split(/[_\-\s]+/)
194
+ .map(word => word.toLowerCase())
195
+ .filter(Boolean);
196
+ }
197
+ function suggestSegment(segment, convention) {
198
+ const words = splitWords(segment);
199
+ if (words.length === 0)
200
+ return segment;
201
+ if (convention === 'snake_case')
202
+ return words.join('_');
203
+ if (convention === 'kebab-case')
204
+ return words.join('-');
205
+ if (convention === 'camelCase') {
206
+ return words[0] + words.slice(1).map(word => word[0].toUpperCase() + word.slice(1)).join('');
207
+ }
208
+ return words.map(word => word[0].toUpperCase() + word.slice(1)).join('');
209
+ }
210
+ /** Suggests per dot-separated segment, matching `checkStem`: the dots in
211
+ * `Shop.Api.Tests` are part of the name, not word separators. */
212
+ function suggestName(stem, convention) {
213
+ if (!stem.includes('.'))
214
+ return suggestSegment(stem, convention);
215
+ return stem
216
+ .split('.')
217
+ .map(segment => suggestSegment(segment, convention))
218
+ .join('.');
219
+ }
220
+ function isExemptPath(filePath) {
221
+ const relative = normalisePath(filePath);
222
+ const parts = relative.split('/').filter(Boolean);
223
+ const fileName = basename(relative);
224
+ const lowerName = fileName.toLowerCase();
225
+ const extension = extensionOf(fileName);
226
+ const stem = stemOf(fileName);
227
+ if (parts.some(part => part.startsWith('.') || GENERATED_DIRS.has(part)))
228
+ return true;
229
+ // Route-construct exemptions apply to the FILE's own name only, never to
230
+ // ancestor folders. A route group `(app)`, private `_modals`, parallel `@slot`,
231
+ // or dynamic `[slug]` FOLDER does not exempt the ordinary files inside it -
232
+ // those still follow the convention. Only a file literally named as a route
233
+ // construct (pages-router `[id].tsx`, or a `_`/`@`-prefixed private file) is exempt.
234
+ if (/^\[\[?\.{0,3}[^\]]+\]\]?$/.test(stem) ||
235
+ /^\(.+\)$/.test(stem) ||
236
+ fileName.startsWith('@') ||
237
+ fileName.startsWith('_') ||
238
+ fileName.startsWith(exports.FILE_NAMING_EXEMPTIONS.svelteKitRoutePrefix))
239
+ return true;
240
+ if (lowerName.endsWith('.d.ts') || lowerName.endsWith('_test.go') || lowerName.endsWith('.pb.go'))
241
+ return true;
242
+ if (PYTHON_RESERVED.has(lowerName) || /^__.+__\.py$/.test(lowerName))
243
+ return true;
244
+ if (lowerName === 'main.go' || stem === 'index')
245
+ return true;
246
+ if (/(?:^|\.)config$/.test(stem) || /^(?:vite|esbuild|webpack|rollup|parcel)$/.test(stem))
247
+ return true;
248
+ if (exports.FILE_NAMING_MULTI_DOT_SUFFIXES.some(suffix => suffix === '.generated' && fileName.includes(`${suffix}.`)))
249
+ return true;
250
+ const underNextRoute = parts.some(part => part === 'app' || part === 'pages');
251
+ if (underNextRoute && NEXT_RESERVED_STEMS.has(stem))
252
+ return true;
253
+ if (NEXT_RESERVED_STEMS.has(stem) && ['middleware', 'instrumentation', 'sitemap', 'robots', 'manifest'].includes(stem))
254
+ return true;
255
+ if (extension === '')
256
+ return true;
257
+ return false;
258
+ }
259
+ function checkFileNaming(relativePath, config) {
260
+ const policy = resolveFileNamingPolicy(relativePath, config.fileNaming);
261
+ if (!policy)
262
+ return null;
263
+ const normalised = normalisePath(relativePath);
264
+ if (isExemptPath(normalised))
265
+ return null;
266
+ const fileName = basename(normalised);
267
+ const extension = extensionOf(fileName);
268
+ const rawStem = fileName.slice(0, fileName.length - extension.length);
269
+ const stem = stemOf(fileName);
270
+ if (checkStem(stem, policy.convention))
271
+ return null;
272
+ const suggestion = `${suggestName(stem, policy.convention)}${rawStem.slice(stem.length)}${extension}`;
273
+ // A stem the word-splitter cannot reshape (leading punctuation, digits only)
274
+ // renames to itself. Reporting that costs a point and offers a Quick Fix and a
275
+ // batch-rename row that do nothing, so treat an unactionable suggestion as no
276
+ // finding at all - the check exists to drive a rename, not to deduct a point.
277
+ if (suggestion === fileName)
278
+ return null;
279
+ return {
280
+ file: normalised,
281
+ line: 1,
282
+ convention: policy.convention,
283
+ actual: fileName,
284
+ suggestion,
285
+ };
286
+ }
287
+ const ALL_CONVENTIONS = ['snake_case', 'kebab-case', 'camelCase', 'PascalCase'];
288
+ /**
289
+ * Infer the naming convention a codebase already follows, so a workspace with
290
+ * no configured policy can be offered a one-click "adopt this" nudge.
291
+ *
292
+ * Single-word stems like `user` are consistent with snake_case, kebab-case and
293
+ * camelCase at once, so they cannot discriminate. The winner is chosen by the
294
+ * plurality of *discriminating* files (those consistent with exactly one
295
+ * convention, e.g. `user_row`, `user-row`, `userRow`, `UserRow`). Returns null
296
+ * when there is not enough discriminating signal to make an honest suggestion.
297
+ */
298
+ function detectDominantConvention(relativePaths, options = {}) {
299
+ const minDiscriminating = options.minDiscriminating ?? 5;
300
+ const minShare = options.minShare ?? 0.6;
301
+ const discriminatingCount = {
302
+ snake_case: 0,
303
+ 'kebab-case': 0,
304
+ camelCase: 0,
305
+ PascalCase: 0,
306
+ };
307
+ let totalConsidered = 0;
308
+ let totalDiscriminating = 0;
309
+ const stems = [];
310
+ for (const filePath of relativePaths) {
311
+ const normalised = normalisePath(filePath);
312
+ if (isExemptPath(normalised))
313
+ continue;
314
+ const stem = stemOf(basename(normalised));
315
+ if (!stem)
316
+ continue;
317
+ totalConsidered++;
318
+ stems.push(stem);
319
+ const consistent = ALL_CONVENTIONS.filter((convention) => checkStem(stem, convention));
320
+ if (consistent.length === 1) {
321
+ discriminatingCount[consistent[0]]++;
322
+ totalDiscriminating++;
323
+ }
324
+ }
325
+ if (totalDiscriminating < minDiscriminating)
326
+ return null;
327
+ let winner = 'kebab-case';
328
+ for (const convention of ALL_CONVENTIONS) {
329
+ if (discriminatingCount[convention] > discriminatingCount[winner])
330
+ winner = convention;
331
+ }
332
+ const winnerShare = discriminatingCount[winner] / totalDiscriminating;
333
+ if (winnerShare < minShare)
334
+ return null;
335
+ const matched = stems.filter((stem) => checkStem(stem, winner)).length;
336
+ return {
337
+ convention: winner,
338
+ matched,
339
+ total: totalConsidered,
340
+ share: totalConsidered > 0 ? matched / totalConsidered : 0,
341
+ };
342
+ }
343
+ //# sourceMappingURL=fileNaming.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileNaming.js","sourceRoot":"","sources":["../src/fileNaming.ts"],"names":[],"mappings":"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"}
package/dist/gate.d.ts ADDED
@@ -0,0 +1,49 @@
1
+ import { FileAnalysis } from './types';
2
+ import { LanguageGateCaps } from './languages';
3
+ export interface GateConfig {
4
+ minScore?: number;
5
+ maxSecrets?: number;
6
+ maxComplexity?: number;
7
+ maxFileLength?: number;
8
+ maxSmellsPerFile?: number;
9
+ maxSecuritySmells?: number;
10
+ maxSuppressions?: number;
11
+ maxDuplicateBlocks?: number;
12
+ maxNamingViolations?: number;
13
+ }
14
+ export type GateRuleType = 'score' | 'secrets' | 'complexity' | 'file-length' | 'smells' | 'security-smells' | 'suppressions' | 'duplicate-blocks' | 'naming-violations';
15
+ export interface GateFailingFile {
16
+ path: string;
17
+ value: number;
18
+ threshold?: number;
19
+ }
20
+ export interface GateFailure {
21
+ rule: GateRuleType;
22
+ threshold: number;
23
+ actual: number;
24
+ files: GateFailingFile[];
25
+ message: string;
26
+ }
27
+ export interface GateSummary {
28
+ workspaceScore: number;
29
+ filesAnalysed: number;
30
+ totalSecrets: number;
31
+ maxComplexity: number;
32
+ maxFileLength: number;
33
+ totalSecuritySmells: number;
34
+ totalSuppressions: number;
35
+ totalDuplicateBlocks: number;
36
+ totalNamingViolations: number;
37
+ }
38
+ export interface GateResult {
39
+ passed: boolean;
40
+ failures: GateFailure[];
41
+ summary: GateSummary;
42
+ }
43
+ export interface GateFileEntry {
44
+ path: string;
45
+ analysis: FileAnalysis;
46
+ caps?: LanguageGateCaps;
47
+ }
48
+ export declare function evaluateGate(config: GateConfig, files: GateFileEntry[]): GateResult;
49
+ //# sourceMappingURL=gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAE9C,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,YAAY,GAAG,aAAa,GAAG,QAAQ,GAAG,iBAAiB,GAAG,cAAc,GAAG,kBAAkB,GAAG,mBAAmB,CAAA;AAExK,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IAGb,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,YAAY,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,eAAe,EAAE,CAAA;IACxB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,MAAM,CAAA;IACrB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,iBAAiB,EAAE,MAAM,CAAA;IACzB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,qBAAqB,EAAE,MAAM,CAAA;CAC9B;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,EAAE,WAAW,EAAE,CAAA;IACvB,OAAO,EAAE,WAAW,CAAA;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,YAAY,CAAA;IAItB,IAAI,CAAC,EAAE,gBAAgB,CAAA;CACxB;AA+CD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,aAAa,EAAE,GACrB,UAAU,CAkPZ"}
package/dist/gate.js ADDED
@@ -0,0 +1,242 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.evaluateGate = evaluateGate;
4
+ function countSmells(analysis) {
5
+ const { codeSmells } = analysis;
6
+ return (codeSmells.consoleLogs.length +
7
+ codeSmells.todos.length +
8
+ codeSmells.deepNesting +
9
+ codeSmells.longParameterLists.length +
10
+ codeSmells.magicNumbers.length +
11
+ codeSmells.unusedVars.length +
12
+ codeSmells.unusedFunctions.length +
13
+ codeSmells.hardcodedSecrets.length +
14
+ (codeSmells.bareSuppressions ?? []).length +
15
+ (codeSmells.fileNamingViolations ?? []).length);
16
+ }
17
+ function countSuppressions(analysis) {
18
+ return (analysis.suppressed ?? []).length;
19
+ }
20
+ // Only primary findings count toward totals: a cross-file block leaves a
21
+ // non-primary mirror on its second file so the same block is never counted twice.
22
+ function countDuplicateBlocks(analysis) {
23
+ return (analysis.codeSmells.duplicateBlocks ?? []).filter(d => d.primary !== false).length;
24
+ }
25
+ function countDuplicateInvolvement(analysis) {
26
+ return (analysis.codeSmells.duplicateBlocks ?? []).length;
27
+ }
28
+ function countSecuritySmells(analysis) {
29
+ const { codeSmells } = analysis;
30
+ return ((codeSmells.evalUsage ?? []).length +
31
+ (codeSmells.sqlConcatenation ?? []).length +
32
+ (codeSmells.insecureRandom ?? []).length +
33
+ (codeSmells.unsafeRegex ?? []).length +
34
+ (codeSmells.hardcodedLocalhost ?? []).length +
35
+ (codeSmells.disabledTlsVerification ?? []).length +
36
+ (codeSmells.debugFlagsEnabled ?? []).length +
37
+ (codeSmells.weakHashing ?? []).length +
38
+ (codeSmells.openRedirect ?? []).length);
39
+ }
40
+ function evaluateGate(config, files) {
41
+ const failures = [];
42
+ if (files.length === 0) {
43
+ return {
44
+ passed: true,
45
+ failures: [],
46
+ summary: {
47
+ workspaceScore: 100,
48
+ filesAnalysed: 0,
49
+ totalSecrets: 0,
50
+ maxComplexity: 0,
51
+ maxFileLength: 0,
52
+ totalSecuritySmells: 0,
53
+ totalSuppressions: 0,
54
+ totalDuplicateBlocks: 0,
55
+ totalNamingViolations: 0,
56
+ },
57
+ };
58
+ }
59
+ let totalScore = 0;
60
+ let totalSecrets = 0;
61
+ let maxComplexity = 0;
62
+ let maxFileLength = 0;
63
+ let totalSecuritySmells = 0;
64
+ let totalSuppressions = 0;
65
+ let totalDuplicateBlocks = 0;
66
+ let totalNamingViolations = 0;
67
+ for (const { analysis } of files) {
68
+ totalScore += analysis.healthScore;
69
+ totalSecrets += analysis.codeSmells.hardcodedSecrets.length;
70
+ totalSecuritySmells += countSecuritySmells(analysis);
71
+ totalSuppressions += countSuppressions(analysis);
72
+ totalDuplicateBlocks += countDuplicateBlocks(analysis);
73
+ totalNamingViolations += (analysis.codeSmells.fileNamingViolations ?? []).length;
74
+ if (analysis.complexityScore > maxComplexity)
75
+ maxComplexity = analysis.complexityScore;
76
+ if (analysis.lineCount > maxFileLength)
77
+ maxFileLength = analysis.lineCount;
78
+ }
79
+ const workspaceScore = Math.floor(totalScore / files.length);
80
+ if (config.minScore !== undefined) {
81
+ const threshold = config.minScore;
82
+ const failing = files
83
+ .filter(({ analysis }) => Math.floor(analysis.healthScore) < threshold)
84
+ .map(({ path, analysis }) => ({ path, value: Math.floor(analysis.healthScore) }))
85
+ .sort((a, b) => a.value - b.value || a.path.localeCompare(b.path));
86
+ if (failing.length > 0) {
87
+ failures.push({
88
+ rule: 'score',
89
+ threshold,
90
+ actual: failing[0].value,
91
+ files: failing,
92
+ message: `${failing.length} file${failing.length !== 1 ? 's' : ''} below minimum score ${threshold}`,
93
+ });
94
+ }
95
+ }
96
+ if (config.maxSecrets !== undefined) {
97
+ const threshold = config.maxSecrets;
98
+ if (totalSecrets > threshold) {
99
+ const failing = files
100
+ .filter(({ analysis }) => analysis.codeSmells.hardcodedSecrets.length > 0)
101
+ .map(({ path, analysis }) => ({ path, value: analysis.codeSmells.hardcodedSecrets.length }))
102
+ .sort((a, b) => b.value - a.value || a.path.localeCompare(b.path));
103
+ failures.push({
104
+ rule: 'secrets',
105
+ threshold,
106
+ actual: totalSecrets,
107
+ files: failing,
108
+ message: `Found ${totalSecrets} hardcoded secret${totalSecrets !== 1 ? 's' : ''} (maximum ${threshold})`,
109
+ });
110
+ }
111
+ }
112
+ if (config.maxComplexity !== undefined) {
113
+ const threshold = config.maxComplexity;
114
+ const failing = files
115
+ .filter(({ analysis }) => analysis.complexityScore > threshold)
116
+ .map(({ path, analysis }) => ({ path, value: analysis.complexityScore }))
117
+ .sort((a, b) => b.value - a.value || a.path.localeCompare(b.path));
118
+ if (failing.length > 0) {
119
+ failures.push({
120
+ rule: 'complexity',
121
+ threshold,
122
+ actual: failing[0].value,
123
+ files: failing,
124
+ message: `${failing.length} file${failing.length !== 1 ? 's' : ''} exceed${failing.length !== 1 ? '' : 's'} maximum complexity ${threshold}`,
125
+ });
126
+ }
127
+ }
128
+ if (config.maxFileLength !== undefined) {
129
+ const threshold = config.maxFileLength;
130
+ const failing = files
131
+ .filter(({ analysis }) => analysis.lineCount > threshold)
132
+ .map(({ path, analysis }) => ({ path, value: analysis.lineCount }))
133
+ .sort((a, b) => b.value - a.value || a.path.localeCompare(b.path));
134
+ if (failing.length > 0) {
135
+ failures.push({
136
+ rule: 'file-length',
137
+ threshold,
138
+ actual: failing[0].value,
139
+ files: failing,
140
+ message: `${failing.length} file${failing.length !== 1 ? 's' : ''} exceed${failing.length !== 1 ? '' : 's'} maximum length of ${threshold} lines`,
141
+ });
142
+ }
143
+ }
144
+ // Per-file rules honour a per-language cap (Phase 5.10) when the entry
145
+ // carries one; the rule also runs when ONLY language caps set a limit, so a
146
+ // config with `gateMaxSmellsPerFile` set solely inside a language block
147
+ // still gates files of that language.
148
+ const evaluatePerFileCapRule = (rule, baseThreshold, capFor, countFor, describe) => {
149
+ const hasAnyCap = files.some(entry => capFor(entry) !== undefined);
150
+ if (baseThreshold === undefined && !hasAnyCap)
151
+ return;
152
+ const failing = [];
153
+ const appliedThresholds = [];
154
+ for (const entry of files) {
155
+ const effective = capFor(entry) ?? baseThreshold;
156
+ if (effective === undefined)
157
+ continue;
158
+ const value = countFor(entry.analysis);
159
+ if (value > effective) {
160
+ failing.push({ path: entry.path, value, threshold: effective });
161
+ appliedThresholds.push(effective);
162
+ }
163
+ }
164
+ failing.sort((a, b) => b.value - a.value || a.path.localeCompare(b.path));
165
+ if (failing.length > 0) {
166
+ const ruleThreshold = baseThreshold ?? Math.min(...appliedThresholds);
167
+ // Only expose per-file thresholds when they diverge from the rule-level
168
+ // one - keeps the common single-threshold output unchanged.
169
+ const normalised = failing.map(file => file.threshold === ruleThreshold ? { path: file.path, value: file.value } : file);
170
+ failures.push({
171
+ rule,
172
+ threshold: ruleThreshold,
173
+ actual: normalised[0].value,
174
+ files: normalised,
175
+ message: describe(normalised.length, ruleThreshold),
176
+ });
177
+ }
178
+ };
179
+ evaluatePerFileCapRule('smells', config.maxSmellsPerFile, entry => entry.caps?.maxSmellsPerFile, countSmells, (failingCount, threshold) => `${failingCount} file${failingCount !== 1 ? 's' : ''} exceed${failingCount !== 1 ? '' : 's'} maximum smell count of ${threshold}`);
180
+ if (config.maxSecuritySmells !== undefined) {
181
+ const threshold = config.maxSecuritySmells;
182
+ if (totalSecuritySmells > threshold) {
183
+ const failing = files
184
+ .filter(({ analysis }) => countSecuritySmells(analysis) > 0)
185
+ .map(({ path, analysis }) => ({ path, value: countSecuritySmells(analysis) }))
186
+ .sort((a, b) => b.value - a.value || a.path.localeCompare(b.path));
187
+ failures.push({
188
+ rule: 'security-smells',
189
+ threshold,
190
+ actual: totalSecuritySmells,
191
+ files: failing,
192
+ message: `Found ${totalSecuritySmells} security smell${totalSecuritySmells !== 1 ? 's' : ''} (maximum ${threshold})`,
193
+ });
194
+ }
195
+ }
196
+ evaluatePerFileCapRule('suppressions', config.maxSuppressions, entry => entry.caps?.maxSuppressions, countSuppressions, (failingCount, threshold) => `${failingCount} file${failingCount !== 1 ? 's' : ''} exceed${failingCount !== 1 ? '' : 's'} maximum suppression count of ${threshold}`);
197
+ if (config.maxDuplicateBlocks !== undefined) {
198
+ const threshold = config.maxDuplicateBlocks;
199
+ if (totalDuplicateBlocks > threshold) {
200
+ const failing = files
201
+ .filter(({ analysis }) => countDuplicateInvolvement(analysis) > 0)
202
+ .map(({ path, analysis }) => ({ path, value: countDuplicateInvolvement(analysis) }))
203
+ .sort((a, b) => b.value - a.value || a.path.localeCompare(b.path));
204
+ failures.push({
205
+ rule: 'duplicate-blocks',
206
+ threshold,
207
+ actual: totalDuplicateBlocks,
208
+ files: failing,
209
+ message: `Found ${totalDuplicateBlocks} duplicate code block${totalDuplicateBlocks !== 1 ? 's' : ''} (maximum ${threshold})`,
210
+ });
211
+ }
212
+ }
213
+ if (config.maxNamingViolations !== undefined && totalNamingViolations > config.maxNamingViolations) {
214
+ const failing = files
215
+ .filter(({ analysis }) => (analysis.codeSmells.fileNamingViolations ?? []).length > 0)
216
+ .map(({ path, analysis }) => ({ path, value: analysis.codeSmells.fileNamingViolations.length }))
217
+ .sort((a, b) => b.value - a.value || a.path.localeCompare(b.path));
218
+ failures.push({
219
+ rule: 'naming-violations',
220
+ threshold: config.maxNamingViolations,
221
+ actual: totalNamingViolations,
222
+ files: failing,
223
+ message: `Found ${totalNamingViolations} file naming violation${totalNamingViolations !== 1 ? 's' : ''} (maximum ${config.maxNamingViolations})`,
224
+ });
225
+ }
226
+ return {
227
+ passed: failures.length === 0,
228
+ failures,
229
+ summary: {
230
+ workspaceScore,
231
+ filesAnalysed: files.length,
232
+ totalSecrets,
233
+ maxComplexity,
234
+ maxFileLength,
235
+ totalSecuritySmells,
236
+ totalSuppressions,
237
+ totalDuplicateBlocks,
238
+ totalNamingViolations,
239
+ },
240
+ };
241
+ }
242
+ //# sourceMappingURL=gate.js.map