@iris-code/core 0.1.0 → 0.1.2
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 +35 -35
- package/package.json +5 -4
- package/dist/slop.d.ts +0 -37
- package/dist/slop.d.ts.map +0 -1
- package/dist/slop.js +0 -81
- package/dist/slop.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
# @iris/core
|
|
2
|
-
|
|
3
|
-
Shared analysis engine package for Iris.
|
|
4
|
-
|
|
5
|
-
## Scope
|
|
6
|
-
|
|
7
|
-
This package is intended to become the single source of truth for:
|
|
8
|
-
|
|
9
|
-
- scoring logic
|
|
10
|
-
- issue normalization
|
|
11
|
-
- shared analysis result types
|
|
12
|
-
- gate evaluation
|
|
13
|
-
- deterministic, density-ranked workspace Quality Signals
|
|
1
|
+
# @iris/core
|
|
2
|
+
|
|
3
|
+
Shared analysis engine package for Iris.
|
|
4
|
+
|
|
5
|
+
## Scope
|
|
6
|
+
|
|
7
|
+
This package is intended to become the single source of truth for:
|
|
8
|
+
|
|
9
|
+
- scoring logic
|
|
10
|
+
- issue normalization
|
|
11
|
+
- shared analysis result types
|
|
12
|
+
- gate evaluation
|
|
13
|
+
- deterministic, density-ranked workspace Quality Signals
|
|
14
14
|
- workspace-wide, path/role-aware, and fallback per-language file naming checks with ordered glob rules, suggestions, and built-in exemptions
|
|
15
15
|
- fixture-backed parity tests used by both the extension and the CLI
|
|
16
16
|
- Vue and Svelte single-file component script extraction with native line preservation
|
|
17
|
-
|
|
18
|
-
## Extraction notes
|
|
19
|
-
|
|
20
|
-
Keep the package pure where possible. Host-specific concerns should stay outside:
|
|
21
|
-
|
|
22
|
-
- VS Code commands, webviews, and SecretStorage stay in `Iris-extension`
|
|
23
|
-
- CLI argument parsing and output formatting can stay in the CLI shell layer
|
|
24
|
-
- `@iris/core` should receive plain source text and config data, then return structured analysis output
|
|
25
|
-
|
|
26
|
-
## Publish-ready surface
|
|
27
|
-
|
|
28
|
-
This package now publishes compiled output from `dist/` rather than exposing raw TypeScript source.
|
|
29
|
-
|
|
30
|
-
- `pnpm run build` compiles the package
|
|
31
|
-
- `pnpm run test` runs the fixture-backed packaged-surface tests
|
|
32
|
-
- `pnpm pack` will build and test first via `prepack`
|
|
33
|
-
|
|
34
|
-
## v1.16 analysis surface
|
|
35
|
-
|
|
36
|
-
`computeQualitySignals` consumes aggregate scan metrics and returns recurring quality signals ranked by density and impact. Each signal preserves its raw count or percentage and carries a simple attention level; it does not create a second workspace score.
|
|
37
|
-
|
|
38
|
-
`checkFileNaming` enforces the workspace naming policy, with a matching language policy taking precedence. `analyseFile` accepts optional `relativePath` and `baselineFiles` context so extension and CLI callers share baseline-aware behavior without core reading the filesystem.
|
|
17
|
+
|
|
18
|
+
## Extraction notes
|
|
19
|
+
|
|
20
|
+
Keep the package pure where possible. Host-specific concerns should stay outside:
|
|
21
|
+
|
|
22
|
+
- VS Code commands, webviews, and SecretStorage stay in `Iris-extension`
|
|
23
|
+
- CLI argument parsing and output formatting can stay in the CLI shell layer
|
|
24
|
+
- `@iris/core` should receive plain source text and config data, then return structured analysis output
|
|
25
|
+
|
|
26
|
+
## Publish-ready surface
|
|
27
|
+
|
|
28
|
+
This package now publishes compiled output from `dist/` rather than exposing raw TypeScript source.
|
|
29
|
+
|
|
30
|
+
- `pnpm run build` compiles the package
|
|
31
|
+
- `pnpm run test` runs the fixture-backed packaged-surface tests
|
|
32
|
+
- `pnpm pack` will build and test first via `prepack`
|
|
33
|
+
|
|
34
|
+
## v1.16 analysis surface
|
|
35
|
+
|
|
36
|
+
`computeQualitySignals` consumes aggregate scan metrics and returns recurring quality signals ranked by density and impact. Each signal preserves its raw count or percentage and carries a simple attention level; it does not create a second workspace score.
|
|
37
|
+
|
|
38
|
+
`checkFileNaming` enforces the workspace naming policy, with a matching language policy taking precedence. `analyseFile` accepts optional `relativePath` and `baselineFiles` context so extension and CLI callers share baseline-aware behavior without core reading the filesystem.
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iris-code/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Shared Iris analysis engine for TypeScript, JavaScript, Vue, Svelte, Go, Python, Ruby, and C#.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
|
-
"url": "https://github.com/Daiveedjay/Iris-package.git",
|
|
7
|
+
"url": "git+https://github.com/Daiveedjay/Iris-package.git",
|
|
8
8
|
"directory": "packages/core"
|
|
9
9
|
},
|
|
10
10
|
"main": "./dist/index.js",
|
|
@@ -27,14 +27,15 @@
|
|
|
27
27
|
"README.md"
|
|
28
28
|
],
|
|
29
29
|
"scripts": {
|
|
30
|
-
"build": "tsc -p tsconfig.json",
|
|
30
|
+
"build": "node -e \"const fs=require('node:fs');fs.rmSync('dist',{recursive:true,force:true});fs.rmSync('tsconfig.tsbuildinfo',{force:true})\" && tsc -p tsconfig.json && node scripts/check-dist-orphans.mjs",
|
|
31
31
|
"typecheck": "tsc -p tsconfig.json --pretty false",
|
|
32
32
|
"test": "pnpm run build && node --test test/core.test.mjs test/gate.test.mjs test/v116.test.mjs test/bench.test.mjs",
|
|
33
33
|
"bench": "pnpm run build && node bench/run.mjs",
|
|
34
34
|
"bench:baseline": "pnpm run build && node bench/run.mjs --baseline",
|
|
35
35
|
"bench:report": "pnpm run build && node bench/run.mjs --report",
|
|
36
36
|
"bench:check": "pnpm run build && node bench/run.mjs --check",
|
|
37
|
-
"prepack": "pnpm run test"
|
|
37
|
+
"prepack": "pnpm run test",
|
|
38
|
+
"clean": "node -e \"const fs=require('node:fs');fs.rmSync('dist',{recursive:true,force:true});fs.rmSync('tsconfig.tsbuildinfo',{force:true})\""
|
|
38
39
|
},
|
|
39
40
|
"license": "MIT",
|
|
40
41
|
"publishConfig": {
|
package/dist/slop.d.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
export type SlopBand = 'clean' | 'drifting' | 'slop';
|
|
2
|
-
export type SlopContributorKey = 'duplication' | 'security' | 'suppressions' | 'type-debt' | 'debug-prints' | 'complexity' | 'todos' | 'file-naming';
|
|
3
|
-
export interface SlopScoreInput {
|
|
4
|
-
totalCodeLines: number;
|
|
5
|
-
fileCount: number;
|
|
6
|
-
typeScriptFileCount: number;
|
|
7
|
-
duplicationPercent: number;
|
|
8
|
-
duplicateBlockCount: number;
|
|
9
|
-
bareSuppressionCount: number;
|
|
10
|
-
suppressedCount: number;
|
|
11
|
-
securitySmellCount: number;
|
|
12
|
-
anyUsageCount: number;
|
|
13
|
-
missingReturnTypeCount: number;
|
|
14
|
-
debugPrintCount: number;
|
|
15
|
-
todoCount: number;
|
|
16
|
-
highComplexityFileCount: number;
|
|
17
|
-
namingViolationCount: number;
|
|
18
|
-
}
|
|
19
|
-
export interface SlopContributor {
|
|
20
|
-
key: SlopContributorKey;
|
|
21
|
-
label: string;
|
|
22
|
-
rawValue: number;
|
|
23
|
-
points: number;
|
|
24
|
-
}
|
|
25
|
-
export interface SlopScoreResult {
|
|
26
|
-
score: number;
|
|
27
|
-
band: SlopBand;
|
|
28
|
-
contributors: SlopContributor[];
|
|
29
|
-
}
|
|
30
|
-
export declare const SLOP_WEIGHTS: Readonly<Record<SlopContributorKey, number>>;
|
|
31
|
-
export declare const SLOP_SATURATION: Readonly<Record<SlopContributorKey, number>>;
|
|
32
|
-
export declare const SLOP_BANDS: {
|
|
33
|
-
readonly cleanMax: 24;
|
|
34
|
-
readonly driftingMax: 54;
|
|
35
|
-
};
|
|
36
|
-
export declare function computeSlopScore(input: SlopScoreInput): SlopScoreResult;
|
|
37
|
-
//# sourceMappingURL=slop.d.ts.map
|
package/dist/slop.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"slop.d.ts","sourceRoot":"","sources":["../src/slop.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAA;AAEpD,MAAM,MAAM,kBAAkB,GAC1B,aAAa,GACb,UAAU,GACV,cAAc,GACd,WAAW,GACX,cAAc,GACd,YAAY,GACZ,OAAO,GACP,aAAa,CAAA;AAEjB,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,kBAAkB,EAAE,MAAM,CAAA;IAC1B,mBAAmB,EAAE,MAAM,CAAA;IAC3B,oBAAoB,EAAE,MAAM,CAAA;IAC5B,eAAe,EAAE,MAAM,CAAA;IACvB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,aAAa,EAAE,MAAM,CAAA;IACrB,sBAAsB,EAAE,MAAM,CAAA;IAC9B,eAAe,EAAE,MAAM,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,uBAAuB,EAAE,MAAM,CAAA;IAC/B,oBAAoB,EAAE,MAAM,CAAA;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,kBAAkB,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,QAAQ,CAAA;IACd,YAAY,EAAE,eAAe,EAAE,CAAA;CAChC;AAED,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,CASrE,CAAA;AAID,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,CASxE,CAAA;AAED,eAAO,MAAM,UAAU;;;CAGb,CAAA;AAYV,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,GAAG,eAAe,CA2CvE"}
|
package/dist/slop.js
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SLOP_BANDS = exports.SLOP_SATURATION = exports.SLOP_WEIGHTS = void 0;
|
|
4
|
-
exports.computeSlopScore = computeSlopScore;
|
|
5
|
-
exports.SLOP_WEIGHTS = {
|
|
6
|
-
duplication: 30,
|
|
7
|
-
security: 20,
|
|
8
|
-
suppressions: 12,
|
|
9
|
-
'type-debt': 12,
|
|
10
|
-
'debug-prints': 8,
|
|
11
|
-
complexity: 10,
|
|
12
|
-
todos: 4,
|
|
13
|
-
'file-naming': 4,
|
|
14
|
-
};
|
|
15
|
-
// Density at which a component reaches its full weight. Counts are per KLOC;
|
|
16
|
-
// duplication is already a percentage.
|
|
17
|
-
exports.SLOP_SATURATION = {
|
|
18
|
-
duplication: 20,
|
|
19
|
-
security: 4,
|
|
20
|
-
suppressions: 3,
|
|
21
|
-
'type-debt': 12,
|
|
22
|
-
'debug-prints': 8,
|
|
23
|
-
complexity: 2,
|
|
24
|
-
todos: 10,
|
|
25
|
-
'file-naming': 5,
|
|
26
|
-
};
|
|
27
|
-
exports.SLOP_BANDS = {
|
|
28
|
-
cleanMax: 24,
|
|
29
|
-
driftingMax: 54,
|
|
30
|
-
};
|
|
31
|
-
function rounded(value) {
|
|
32
|
-
return Math.round(value * 10) / 10;
|
|
33
|
-
}
|
|
34
|
-
function bandFor(score) {
|
|
35
|
-
if (score <= exports.SLOP_BANDS.cleanMax)
|
|
36
|
-
return 'clean';
|
|
37
|
-
if (score <= exports.SLOP_BANDS.driftingMax)
|
|
38
|
-
return 'drifting';
|
|
39
|
-
return 'slop';
|
|
40
|
-
}
|
|
41
|
-
function computeSlopScore(input) {
|
|
42
|
-
if (input.fileCount <= 0 || input.totalCodeLines <= 0) {
|
|
43
|
-
return { score: 0, band: 'clean', contributors: [] };
|
|
44
|
-
}
|
|
45
|
-
const kloc = Math.max(input.totalCodeLines / 1000, 0.1);
|
|
46
|
-
const raw = {
|
|
47
|
-
duplication: Math.max(0, input.duplicationPercent),
|
|
48
|
-
security: Math.max(0, input.securitySmellCount) / kloc,
|
|
49
|
-
suppressions: Math.max(0, input.bareSuppressionCount + input.suppressedCount * 0.25) / kloc,
|
|
50
|
-
'type-debt': Math.max(0, input.anyUsageCount + input.missingReturnTypeCount) / kloc,
|
|
51
|
-
'debug-prints': Math.max(0, input.debugPrintCount) / kloc,
|
|
52
|
-
complexity: Math.max(0, input.highComplexityFileCount) / kloc,
|
|
53
|
-
todos: Math.max(0, input.todoCount) / kloc,
|
|
54
|
-
'file-naming': Math.max(0, input.namingViolationCount) / kloc,
|
|
55
|
-
};
|
|
56
|
-
const applicable = Object.keys(exports.SLOP_WEIGHTS)
|
|
57
|
-
.filter(key => key !== 'type-debt' || input.typeScriptFileCount > 0);
|
|
58
|
-
const applicableWeight = applicable.reduce((sum, key) => sum + exports.SLOP_WEIGHTS[key], 0);
|
|
59
|
-
const scale = applicableWeight > 0 ? 100 / applicableWeight : 1;
|
|
60
|
-
const contributors = applicable
|
|
61
|
-
.map((key) => ({
|
|
62
|
-
key,
|
|
63
|
-
label: {
|
|
64
|
-
duplication: 'Duplication',
|
|
65
|
-
security: 'Security smells',
|
|
66
|
-
suppressions: 'Suppressions',
|
|
67
|
-
'type-debt': 'Type debt',
|
|
68
|
-
'debug-prints': 'Debug prints',
|
|
69
|
-
complexity: 'Complexity spikes',
|
|
70
|
-
todos: 'TODO load',
|
|
71
|
-
'file-naming': 'File naming',
|
|
72
|
-
}[key],
|
|
73
|
-
rawValue: rounded(raw[key]),
|
|
74
|
-
points: rounded(Math.min(1, raw[key] / exports.SLOP_SATURATION[key]) * exports.SLOP_WEIGHTS[key] * scale),
|
|
75
|
-
}))
|
|
76
|
-
.filter(contributor => contributor.points > 0)
|
|
77
|
-
.sort((a, b) => b.points - a.points || a.label.localeCompare(b.label));
|
|
78
|
-
const score = Math.max(0, Math.min(100, Math.round(contributors.reduce((sum, item) => sum + item.points, 0))));
|
|
79
|
-
return { score, band: bandFor(score), contributors };
|
|
80
|
-
}
|
|
81
|
-
//# sourceMappingURL=slop.js.map
|
package/dist/slop.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"slop.js","sourceRoot":"","sources":["../src/slop.ts"],"names":[],"mappings":"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"}
|