@cofferdam/check-sdk 0.2.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 +120 -0
- package/dist/ast.d.ts +120 -0
- package/dist/ast.d.ts.map +1 -0
- package/dist/ast.js +21 -0
- package/dist/ast.js.map +1 -0
- package/dist/category.d.ts +9 -0
- package/dist/category.d.ts.map +1 -0
- package/dist/category.js +15 -0
- package/dist/category.js.map +1 -0
- package/dist/check-context.d.ts +73 -0
- package/dist/check-context.d.ts.map +1 -0
- package/dist/check-context.js +7 -0
- package/dist/check-context.js.map +1 -0
- package/dist/define-check.d.ts +105 -0
- package/dist/define-check.d.ts.map +1 -0
- package/dist/define-check.js +57 -0
- package/dist/define-check.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/line-view.d.ts +25 -0
- package/dist/line-view.d.ts.map +1 -0
- package/dist/line-view.js +21 -0
- package/dist/line-view.js.map +1 -0
- package/dist/loader.d.ts +32 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +74 -0
- package/dist/loader.js.map +1 -0
- package/dist/options.d.ts +37 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +16 -0
- package/dist/options.js.map +1 -0
- package/dist/plugin-host.d.ts +64 -0
- package/dist/plugin-host.d.ts.map +1 -0
- package/dist/plugin-host.js +129 -0
- package/dist/plugin-host.js.map +1 -0
- package/dist/severity.d.ts +9 -0
- package/dist/severity.d.ts.map +1 -0
- package/dist/severity.js +14 -0
- package/dist/severity.js.map +1 -0
- package/dist/span.d.ts +15 -0
- package/dist/span.d.ts.map +1 -0
- package/dist/span.js +9 -0
- package/dist/span.js.map +1 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# @cofferdam/check-sdk
|
|
2
|
+
|
|
3
|
+
Author [cofferdam](https://github.com/TAJD/cofferdam) plugin checks in TypeScript.
|
|
4
|
+
|
|
5
|
+
`cofferdam` is a code-quality analyzer for TypeScript with a Rust core. The built-in checks cover the common ground (complexity, dead exports, triple-equals, etc); this SDK lets you express **project-specific architectural rules** as checks the same engine runs alongside the built-ins.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm add -D @cofferdam/check-sdk # pnpm
|
|
11
|
+
npm install -D @cofferdam/check-sdk # npm
|
|
12
|
+
yarn add -D @cofferdam/check-sdk # yarn
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The SDK ships compiled JS + types; no runtime dependencies. Node 16+.
|
|
16
|
+
|
|
17
|
+
## Hello check
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// my-checks/no-rovikore.ts
|
|
21
|
+
import { Category, defineCheck, Severity } from "@cofferdam/check-sdk";
|
|
22
|
+
|
|
23
|
+
export default defineCheck({
|
|
24
|
+
id: "BrandCasing",
|
|
25
|
+
category: Category.Warning,
|
|
26
|
+
basePriority: 15,
|
|
27
|
+
defaultSeverity: Severity.High,
|
|
28
|
+
explanation: "Brand must be spelled ROVIKORE.",
|
|
29
|
+
files: { extensions: ["ts", "tsx"] },
|
|
30
|
+
options: {
|
|
31
|
+
brand: { default: "ROVIKORE", type: "string" },
|
|
32
|
+
},
|
|
33
|
+
run(file, ctx, opts) {
|
|
34
|
+
for (const line of file.lines()) {
|
|
35
|
+
// Pattern A — line walk. Skip comments and skip non-string content
|
|
36
|
+
// so we don't false-positive on identifiers / JSX text.
|
|
37
|
+
if (line.isComment || line.isJsxText) continue;
|
|
38
|
+
if (!line.isStringLiteral) continue;
|
|
39
|
+
const m = /\bRovikore\b/.exec(line.text);
|
|
40
|
+
if (!m) continue;
|
|
41
|
+
ctx.report({
|
|
42
|
+
message: `Brand must be ${opts.brand}, not ${m[0]}.`,
|
|
43
|
+
span: line.spanFor(m.index, m.index + m[0].length),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Wire it into `cofferdam.toml`:
|
|
51
|
+
|
|
52
|
+
```toml
|
|
53
|
+
plugins = ["./my-checks/no-rovikore.ts"]
|
|
54
|
+
|
|
55
|
+
[checks."BrandCasing"]
|
|
56
|
+
brand = "ROVIKORE"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Then `cofferdam check src/` runs your plugin alongside every built-in check. Findings flow through the same priority computation, suppression directives, baseline diffing, and output formats.
|
|
60
|
+
|
|
61
|
+
## Three patterns
|
|
62
|
+
|
|
63
|
+
The SDK supports three check shapes, each suited to a different rule class:
|
|
64
|
+
|
|
65
|
+
- **Pattern A — line walk.** `for (const line of file.lines()) { … }`. Best for content checks against string literals or comments (brand spelling, banned words, license headers). The fastest path; no AST parse needed.
|
|
66
|
+
- **Pattern B — AST findAll.** `file.ast.findAll("CallExpression")`, `findAll("ImportDeclaration")`. Best when the rule is a tag-and-match against specific node kinds (banned imports, forbidden API calls).
|
|
67
|
+
- **Pattern C — stateful walk.** `file.ast.walk(visitor)` with accumulator state, decided per-file. Best when the rule depends on inter-statement context (tenant scoping across queries, accumulator-vs-mutator analysis).
|
|
68
|
+
|
|
69
|
+
`AstView` exposes 9 node kinds today: `Program`, `CallExpression`, `ImportDeclaration`, `Function`, `ArrowFunctionExpression`, `Class`, `ObjectExpression`, `MemberExpression`, `IdentifierReference`. The set is additive — new kinds can land in minor releases without breaking existing plugins.
|
|
70
|
+
|
|
71
|
+
## API surface
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import {
|
|
75
|
+
defineCheck, // factory — returns a Check
|
|
76
|
+
Category, // Consistency | Design | Readability | Refactor | Warning
|
|
77
|
+
Severity, // Info | Low | Medium | High | Critical
|
|
78
|
+
Walk, // visitor return: Continue | Skip
|
|
79
|
+
} from "@cofferdam/check-sdk";
|
|
80
|
+
|
|
81
|
+
import type {
|
|
82
|
+
Check, CheckContext, ReportArgs, Fix,
|
|
83
|
+
SourceFile, LineView, Span, RelatedSpan,
|
|
84
|
+
AstView, AstVisitor, AstNode, NodeKind,
|
|
85
|
+
// Per-kind typed nodes:
|
|
86
|
+
ProgramNode, CallExpressionNode, ImportDeclarationNode,
|
|
87
|
+
FunctionNode, ArrowFunctionExpressionNode, ClassNode,
|
|
88
|
+
ObjectExpressionNode, MemberExpressionNode, IdentifierReferenceNode,
|
|
89
|
+
// Options schema helpers:
|
|
90
|
+
OptionKind, OptionSpec, OptionsSchema, ResolvedOptions,
|
|
91
|
+
} from "@cofferdam/check-sdk";
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Everything in this list is part of the stability contract; new exports are additive. Removing or renaming an export is a breaking change.
|
|
95
|
+
|
|
96
|
+
## Versioning
|
|
97
|
+
|
|
98
|
+
The SDK ships in lockstep with the cofferdam binary. `@cofferdam/check-sdk@X.Y.Z` is built and tested against `cofferdam@X.Y.Z`; the cofferdam plugin host enforces a major-version compatibility check at load time and refuses to run plugins whose vendored SDK is from a different major.
|
|
99
|
+
|
|
100
|
+
For 0.x: minor bumps may be breaking. Pin both packages to the same exact version until 1.0:
|
|
101
|
+
|
|
102
|
+
```jsonc
|
|
103
|
+
{
|
|
104
|
+
"devDependencies": {
|
|
105
|
+
"cofferdam": "0.2.2",
|
|
106
|
+
"@cofferdam/check-sdk": "0.2.2"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Documentation
|
|
112
|
+
|
|
113
|
+
- Full plugin authoring guide (with worked examples for all three patterns): <https://tajd.github.io/cofferdam>
|
|
114
|
+
- AST surface reference: [`design/sdk-ast-surface.md`](https://github.com/TAJD/cofferdam/blob/main/design/sdk-ast-surface.md)
|
|
115
|
+
- AST wire format (Rust ↔ Node host): [`design/sdk-ast-wire.md`](https://github.com/TAJD/cofferdam/blob/main/design/sdk-ast-wire.md)
|
|
116
|
+
- Three end-to-end fixtures (working plugins): [`examples-plugins/`](https://github.com/TAJD/cofferdam/tree/main/examples-plugins)
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
MIT.
|
package/dist/ast.d.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { Span } from "./span.js";
|
|
2
|
+
/** Outcome of an AstVisitor visit. Controls per-node descent. */
|
|
3
|
+
export declare const Walk: {
|
|
4
|
+
readonly Continue: "continue";
|
|
5
|
+
readonly Skip: "skip";
|
|
6
|
+
};
|
|
7
|
+
export type Walk = (typeof Walk)[keyof typeof Walk];
|
|
8
|
+
/**
|
|
9
|
+
* Kinds exposed via {@link AstView.findAll} and the {@link AstNode}
|
|
10
|
+
* union. Deliberately a small set covering the rovikore-host plugin
|
|
11
|
+
* patterns; grows as plugin needs surface.
|
|
12
|
+
*
|
|
13
|
+
* v0 freeze: cd-717 (`design/sdk-ast-surface.md`). 5 strict +
|
|
14
|
+
* 4 borderline kinds. `NewExpression`, `BinaryExpression`,
|
|
15
|
+
* `StringLiteral`, `NumericLiteral` are deferred until a fixture
|
|
16
|
+
* justifies them — adding kinds is non-breaking, removing isn't.
|
|
17
|
+
*/
|
|
18
|
+
export type NodeKind = "Program" | "CallExpression" | "ImportDeclaration" | "Function" | "ArrowFunctionExpression" | "Class" | "ObjectExpression" | "MemberExpression" | "IdentifierReference";
|
|
19
|
+
/**
|
|
20
|
+
* Common base for every AST node exposed across the FFI. Concrete
|
|
21
|
+
* kinds extend this with their own typed properties.
|
|
22
|
+
*/
|
|
23
|
+
export interface AstNodeBase<K extends NodeKind> {
|
|
24
|
+
readonly kind: K;
|
|
25
|
+
readonly span: Span;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The Program root — entry point for `view.root`. Body holds top-level
|
|
29
|
+
* statements; iterate it for declarations / imports / exports without
|
|
30
|
+
* walking the rest of the tree.
|
|
31
|
+
*
|
|
32
|
+
* Added in cd-svf to make `view.root: AstNode` typeable. Without
|
|
33
|
+
* Program in the union, root narrows to `never` on any TS switch.
|
|
34
|
+
*/
|
|
35
|
+
export interface ProgramNode extends AstNodeBase<"Program"> {
|
|
36
|
+
readonly body: readonly AstNode[];
|
|
37
|
+
}
|
|
38
|
+
export interface CallExpressionNode extends AstNodeBase<"CallExpression"> {
|
|
39
|
+
/** The callee expression — typically an `IdentifierReference` or `MemberExpression`. */
|
|
40
|
+
readonly callee: AstNode;
|
|
41
|
+
readonly arguments: readonly AstNode[];
|
|
42
|
+
}
|
|
43
|
+
export interface ImportDeclarationNode extends AstNodeBase<"ImportDeclaration"> {
|
|
44
|
+
/** The module specifier, e.g. `"axios"`. */
|
|
45
|
+
readonly source: string;
|
|
46
|
+
/** Each specifier's local name. */
|
|
47
|
+
readonly specifiers: readonly {
|
|
48
|
+
readonly localName: string;
|
|
49
|
+
readonly imported?: string;
|
|
50
|
+
}[];
|
|
51
|
+
}
|
|
52
|
+
export interface FunctionNode extends AstNodeBase<"Function"> {
|
|
53
|
+
readonly name: string | undefined;
|
|
54
|
+
readonly params: readonly AstNode[];
|
|
55
|
+
readonly async: boolean;
|
|
56
|
+
readonly generator: boolean;
|
|
57
|
+
}
|
|
58
|
+
export interface ArrowFunctionExpressionNode extends AstNodeBase<"ArrowFunctionExpression"> {
|
|
59
|
+
readonly params: readonly AstNode[];
|
|
60
|
+
readonly async: boolean;
|
|
61
|
+
readonly expression: boolean;
|
|
62
|
+
}
|
|
63
|
+
export interface ClassNode extends AstNodeBase<"Class"> {
|
|
64
|
+
readonly name: string | undefined;
|
|
65
|
+
}
|
|
66
|
+
export interface ObjectExpressionNode extends AstNodeBase<"ObjectExpression"> {
|
|
67
|
+
readonly properties: readonly AstNode[];
|
|
68
|
+
}
|
|
69
|
+
export interface MemberExpressionNode extends AstNodeBase<"MemberExpression"> {
|
|
70
|
+
readonly object: AstNode;
|
|
71
|
+
/** For `.foo` / `["foo"]`, the resolved property name when statically determinable. */
|
|
72
|
+
readonly property: string | undefined;
|
|
73
|
+
readonly computed: boolean;
|
|
74
|
+
}
|
|
75
|
+
export interface IdentifierReferenceNode extends AstNodeBase<"IdentifierReference"> {
|
|
76
|
+
readonly name: string;
|
|
77
|
+
}
|
|
78
|
+
/** Discriminated union of every node kind {@link AstView} surfaces. */
|
|
79
|
+
export type AstNode = ProgramNode | CallExpressionNode | ImportDeclarationNode | FunctionNode | ArrowFunctionExpressionNode | ClassNode | ObjectExpressionNode | MemberExpressionNode | IdentifierReferenceNode;
|
|
80
|
+
/** Map from kind string to typed node — drives `findAll`'s return type. */
|
|
81
|
+
export type NodeOfKind<K extends NodeKind> = Extract<AstNode, {
|
|
82
|
+
kind: K;
|
|
83
|
+
}>;
|
|
84
|
+
/**
|
|
85
|
+
* Visitor passed to {@link AstView.walk}. Override only the kinds you
|
|
86
|
+
* care about; defaults are `Walk.Continue` no-ops. Returning
|
|
87
|
+
* `Walk.Skip` stops descent into that node only — sibling nodes still
|
|
88
|
+
* visit.
|
|
89
|
+
*/
|
|
90
|
+
export interface AstVisitor {
|
|
91
|
+
visitProgram?(node: ProgramNode): Walk;
|
|
92
|
+
visitCallExpression?(node: CallExpressionNode): Walk;
|
|
93
|
+
visitImportDeclaration?(node: ImportDeclarationNode): Walk;
|
|
94
|
+
visitFunction?(node: FunctionNode): Walk;
|
|
95
|
+
visitArrowFunctionExpression?(node: ArrowFunctionExpressionNode): Walk;
|
|
96
|
+
visitClass?(node: ClassNode): Walk;
|
|
97
|
+
visitObjectExpression?(node: ObjectExpressionNode): Walk;
|
|
98
|
+
visitMemberExpression?(node: MemberExpressionNode): Walk;
|
|
99
|
+
visitIdentifierReference?(node: IdentifierReferenceNode): Walk;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Borrowed view of a parsed file's AST. Cheap to construct; cofferdam's
|
|
103
|
+
* napi loader builds one per file per check invocation.
|
|
104
|
+
*/
|
|
105
|
+
export interface AstView {
|
|
106
|
+
/** Direct access to the program root for surgical inspection. */
|
|
107
|
+
readonly root: AstNode;
|
|
108
|
+
/**
|
|
109
|
+
* Eagerly collect every node of `kind` in document order. O(N) over
|
|
110
|
+
* the AST. Allocates an array. For multi-kind queries prefer a single
|
|
111
|
+
* {@link walk} pass.
|
|
112
|
+
*/
|
|
113
|
+
findAll<K extends NodeKind>(kind: K): readonly NodeOfKind<K>[];
|
|
114
|
+
/**
|
|
115
|
+
* Run a stateful visitor over the tree. See {@link AstVisitor} for
|
|
116
|
+
* the per-kind callbacks.
|
|
117
|
+
*/
|
|
118
|
+
walk(visitor: AstVisitor): void;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=ast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../src/ast.ts"],"names":[],"mappings":"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"}
|
package/dist/ast.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// AST surface for plugins (cd-81a.2). Mirrors cofferdam_core::ast — a
|
|
3
|
+
// thin TS proxy over oxc's parsed tree. The napi loader serializes the
|
|
4
|
+
// shape across the FFI boundary so plugins program against this.
|
|
5
|
+
//
|
|
6
|
+
// Three access patterns:
|
|
7
|
+
//
|
|
8
|
+
// 1. Eager filter — `view.findAll("CallExpression")` returns every node
|
|
9
|
+
// of the given kind in document order.
|
|
10
|
+
// 2. Stateful walk — `view.walk(visitor)`. Each visit method returns
|
|
11
|
+
// `Walk.Continue` or `Walk.Skip` to control descent.
|
|
12
|
+
// 3. Direct rooted access — `view.root` for surgical inspection. Escape
|
|
13
|
+
// hatch when the kinds we expose don't cover the case yet.
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.Walk = void 0;
|
|
16
|
+
/** Outcome of an AstVisitor visit. Controls per-node descent. */
|
|
17
|
+
exports.Walk = {
|
|
18
|
+
Continue: "continue",
|
|
19
|
+
Skip: "skip",
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=ast.js.map
|
package/dist/ast.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast.js","sourceRoot":"","sources":["../src/ast.ts"],"names":[],"mappings":";AAAA,sEAAsE;AACtE,uEAAuE;AACvE,iEAAiE;AACjE,EAAE;AACF,yBAAyB;AACzB,EAAE;AACF,wEAAwE;AACxE,0CAA0C;AAC1C,qEAAqE;AACrE,wDAAwD;AACxD,wEAAwE;AACxE,8DAA8D;;;AAI9D,iEAAiE;AACpD,QAAA,IAAI,GAAG;IAClB,QAAQ,EAAE,UAAU;IACpB,IAAI,EAAE,MAAM;CACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const Category: {
|
|
2
|
+
readonly Consistency: "consistency";
|
|
3
|
+
readonly Design: "design";
|
|
4
|
+
readonly Readability: "readability";
|
|
5
|
+
readonly Refactor: "refactor";
|
|
6
|
+
readonly Warning: "warning";
|
|
7
|
+
};
|
|
8
|
+
export type Category = (typeof Category)[keyof typeof Category];
|
|
9
|
+
//# sourceMappingURL=category.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"category.d.ts","sourceRoot":"","sources":["../src/category.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,QAAQ;;;;;;CAMX,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC"}
|
package/dist/category.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Mirror of cofferdam_core::Category. The Rust enum serializes as the
|
|
3
|
+
// lowercase variant ("warning", "design", ...); we hold both shapes so
|
|
4
|
+
// authors can write `Category.Warning` for ergonomics and the engine
|
|
5
|
+
// always reads the wire form.
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.Category = void 0;
|
|
8
|
+
exports.Category = {
|
|
9
|
+
Consistency: "consistency",
|
|
10
|
+
Design: "design",
|
|
11
|
+
Readability: "readability",
|
|
12
|
+
Refactor: "refactor",
|
|
13
|
+
Warning: "warning",
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=category.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"category.js","sourceRoot":"","sources":["../src/category.ts"],"names":[],"mappings":";AAAA,sEAAsE;AACtE,uEAAuE;AACvE,qEAAqE;AACrE,8BAA8B;;;AAEjB,QAAA,QAAQ,GAAG;IACtB,WAAW,EAAE,aAAa;IAC1B,MAAM,EAAE,QAAQ;IAChB,WAAW,EAAE,aAAa;IAC1B,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;CACV,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { AstView } from "./ast.js";
|
|
2
|
+
import type { Severity } from "./severity.js";
|
|
3
|
+
import type { LineView } from "./line-view.js";
|
|
4
|
+
import type { Span } from "./span.js";
|
|
5
|
+
/** A source file passed to a check's `run` callback. */
|
|
6
|
+
export interface SourceFile {
|
|
7
|
+
/** Absolute path as cofferdam discovered it. Forward-slashed on every host. */
|
|
8
|
+
readonly path: string;
|
|
9
|
+
/** Full text of the file, UTF-8. Byte offsets in spans index into this. */
|
|
10
|
+
readonly text: string;
|
|
11
|
+
/**
|
|
12
|
+
* Iterate every line in the file with classification flags drawn
|
|
13
|
+
* from the comment table + an AST walk over string/template/JSX.
|
|
14
|
+
* See {@link LineView} for flag semantics.
|
|
15
|
+
*/
|
|
16
|
+
lines(): IterableIterator<LineView>;
|
|
17
|
+
/**
|
|
18
|
+
* Plugin-facing AST view. `null` only when parsing produced no
|
|
19
|
+
* usable program (the engine emitted `Warning.ParseError` for those
|
|
20
|
+
* files — your check is not invoked again on the failed file).
|
|
21
|
+
*/
|
|
22
|
+
readonly ast: AstView | null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A single mechanical fix: replace the bytes in `span` with `replacement`.
|
|
26
|
+
* Mirrors `cofferdam_core::TextEdit`. Plugin authors attach this at
|
|
27
|
+
* report time; the cofferdam fix engine prefers it over the built-in
|
|
28
|
+
* `Check::autofix` trait method (cd-81a.6).
|
|
29
|
+
*
|
|
30
|
+
* Edits must be non-overlapping; the fix engine applies them in reverse
|
|
31
|
+
* byte-offset order so earlier replacements don't invalidate later spans.
|
|
32
|
+
*/
|
|
33
|
+
export interface Fix {
|
|
34
|
+
readonly span: Span;
|
|
35
|
+
readonly replacement: string;
|
|
36
|
+
}
|
|
37
|
+
/** Per-issue payload passed to {@link CheckContext.report}. */
|
|
38
|
+
export interface ReportArgs {
|
|
39
|
+
/** Required. Human-readable problem description. */
|
|
40
|
+
readonly message: string;
|
|
41
|
+
/** Required. Where the issue lives. Build via `LineView.spanFor` or
|
|
42
|
+
* `SourceFile.ast` node spans. */
|
|
43
|
+
readonly span: Span;
|
|
44
|
+
/**
|
|
45
|
+
* Optional severity override for this specific finding. Defaults to
|
|
46
|
+
* the check's `defaultSeverity` declared on `defineCheck`.
|
|
47
|
+
*/
|
|
48
|
+
readonly severity?: Severity;
|
|
49
|
+
/**
|
|
50
|
+
* Optional secondary locations participating in the same finding —
|
|
51
|
+
* e.g. the duplicate of a duplicate-block, the other declarer of a
|
|
52
|
+
* duplicate-export. Omitted from JSON when empty.
|
|
53
|
+
*/
|
|
54
|
+
readonly related?: readonly {
|
|
55
|
+
readonly file: string;
|
|
56
|
+
readonly span: Span;
|
|
57
|
+
}[];
|
|
58
|
+
/**
|
|
59
|
+
* Optional autofix payload. When present, `cofferdam fix` applies it
|
|
60
|
+
* in place of any built-in autofix logic for this check.
|
|
61
|
+
*/
|
|
62
|
+
readonly fix?: Fix;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Mutable per-file scratch passed to `Check.run`. The check emits
|
|
66
|
+
* findings via `ctx.report(...)`; the engine collects, suppresses,
|
|
67
|
+
* baselines, and renders.
|
|
68
|
+
*/
|
|
69
|
+
export interface CheckContext {
|
|
70
|
+
/** Emit a finding. Calls accumulate; order is preserved. */
|
|
71
|
+
report(args: ReportArgs): void;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=check-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-context.d.ts","sourceRoot":"","sources":["../src/check-context.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,wDAAwD;AACxD,MAAM,WAAW,UAAU;IACzB,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;;OAIG;IACH,KAAK,IAAI,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAEpC;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,GAAG;IAClB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,+DAA+D;AAC/D,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;uCACmC;IACnC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;KAAE,EAAE,CAAC;IAC7E;;;OAGG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,4DAA4D;IAC5D,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;CAChC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SourceFile + CheckContext — the per-file scratch passed to a check's
|
|
3
|
+
// `run(file, ctx, opts)` callback. Mirrors cofferdam_core::CheckContext
|
|
4
|
+
// minus the bits that are only meaningful in the Rust pipeline (corpus,
|
|
5
|
+
// FinalizeContext — those land in their own beads).
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
//# sourceMappingURL=check-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-context.js","sourceRoot":"","sources":["../src/check-context.ts"],"names":[],"mappings":";AAAA,uEAAuE;AACvE,wEAAwE;AACxE,wEAAwE;AACxE,oDAAoD"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { Category } from "./category.js";
|
|
2
|
+
import type { CheckContext, SourceFile } from "./check-context.js";
|
|
3
|
+
import type { OptionsSchema, ResolvedOptions } from "./options.js";
|
|
4
|
+
import type { Severity } from "./severity.js";
|
|
5
|
+
/**
|
|
6
|
+
* Declarative file-scope filter (cd-81a.5). When set, the engine
|
|
7
|
+
* pre-filters discovered files against this scope before invoking
|
|
8
|
+
* `run()`. Replaces the `scannable?` boilerplate that rovikore-host
|
|
9
|
+
* checks ship today.
|
|
10
|
+
*/
|
|
11
|
+
export interface FileScope {
|
|
12
|
+
/** File extensions (without leading dot). Empty/omitted = any. */
|
|
13
|
+
readonly extensions?: readonly string[];
|
|
14
|
+
/**
|
|
15
|
+
* Optional include glob (gitignore syntax via globset). When set,
|
|
16
|
+
* the file path must match.
|
|
17
|
+
*/
|
|
18
|
+
readonly pathPattern?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Exclude globs. Paths matching any of these are skipped, even if
|
|
21
|
+
* `pathPattern` matched.
|
|
22
|
+
*/
|
|
23
|
+
readonly excludePatterns?: readonly string[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The shape `defineCheck` returns — what the napi loader picks up
|
|
27
|
+
* from the plugin module's default export. Holds the static metadata
|
|
28
|
+
* + the `run` callback.
|
|
29
|
+
*
|
|
30
|
+
* The `_optionsKeyType` field is a phantom (never set at runtime); it
|
|
31
|
+
* pins the schema shape into the type so the loader can pass typed
|
|
32
|
+
* `opts` without TS losing inference.
|
|
33
|
+
*/
|
|
34
|
+
export interface Check<S extends OptionsSchema = OptionsSchema> {
|
|
35
|
+
readonly id: string;
|
|
36
|
+
readonly category: Category;
|
|
37
|
+
readonly basePriority: number;
|
|
38
|
+
readonly defaultSeverity: Severity;
|
|
39
|
+
readonly explanation: string;
|
|
40
|
+
/** Optional long-form catalog body used by `cofferdam explain --full`. */
|
|
41
|
+
readonly body: string | undefined;
|
|
42
|
+
/** Whether the check needs full type-aware analysis (routes through ts-morph). */
|
|
43
|
+
readonly requiresTypes: boolean;
|
|
44
|
+
/** Two-pass consistency mode. */
|
|
45
|
+
readonly consistency: boolean;
|
|
46
|
+
readonly options: S;
|
|
47
|
+
/** File-scope filter. `undefined` = applies to every file. */
|
|
48
|
+
readonly files: FileScope | undefined;
|
|
49
|
+
run(file: SourceFile, ctx: CheckContext, opts: ResolvedOptions<S>): void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Input to `defineCheck`. Same shape as {@link Check} but the schema
|
|
53
|
+
* generic is inferred at the call site. Optional fields may be omitted
|
|
54
|
+
* (TS picks the conservative default).
|
|
55
|
+
*/
|
|
56
|
+
export interface DefineCheckInput<S extends OptionsSchema> {
|
|
57
|
+
readonly id: string;
|
|
58
|
+
readonly category: Category;
|
|
59
|
+
readonly basePriority: number;
|
|
60
|
+
/** Defaults to `Severity.Medium` if omitted. */
|
|
61
|
+
readonly defaultSeverity?: Severity;
|
|
62
|
+
readonly explanation: string;
|
|
63
|
+
readonly body?: string;
|
|
64
|
+
readonly requiresTypes?: boolean;
|
|
65
|
+
readonly consistency?: boolean;
|
|
66
|
+
/** Schema; defaults to `{}`. Inferred at the call site. */
|
|
67
|
+
readonly options?: S;
|
|
68
|
+
/** File-scope filter; defaults to "every file". */
|
|
69
|
+
readonly files?: FileScope;
|
|
70
|
+
run(file: SourceFile, ctx: CheckContext, opts: ResolvedOptions<S>): void;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Author a cofferdam plugin check. The call site is the contract: the
|
|
74
|
+
* value passed in is the value the napi loader receives, with TS
|
|
75
|
+
* inference flowing from `options` into `run`'s third argument.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* import { defineCheck, Category, Severity } from "@cofferdam/check-sdk";
|
|
79
|
+
*
|
|
80
|
+
* export default defineCheck({
|
|
81
|
+
* id: "BrandCasing",
|
|
82
|
+
* category: Category.Warning,
|
|
83
|
+
* basePriority: 15,
|
|
84
|
+
* explanation: "Brand name must be all-caps in user-facing copy.",
|
|
85
|
+
* options: {
|
|
86
|
+
* brand: { default: "ROVIKORE", type: "string" },
|
|
87
|
+
* allowedAliases: { default: [] as string[], type: "string[]" },
|
|
88
|
+
* },
|
|
89
|
+
* run(file, ctx, opts) {
|
|
90
|
+
* for (const ln of file.lines()) {
|
|
91
|
+
* if (ln.isComment) continue;
|
|
92
|
+
* if (!ln.isStringLiteral) continue;
|
|
93
|
+
* const m = /\bRovikore\b/.exec(ln.text);
|
|
94
|
+
* if (!m) continue;
|
|
95
|
+
* if (opts.allowedAliases.some((a) => ln.text.includes(a))) continue;
|
|
96
|
+
* ctx.report({
|
|
97
|
+
* message: `Brand name must be "${opts.brand}", not "${m[0]}".`,
|
|
98
|
+
* span: ln.spanFor(m.index, m.index + m[0].length),
|
|
99
|
+
* });
|
|
100
|
+
* }
|
|
101
|
+
* },
|
|
102
|
+
* });
|
|
103
|
+
*/
|
|
104
|
+
export declare function defineCheck<const S extends OptionsSchema = {}>(input: DefineCheckInput<S>): Check<S>;
|
|
105
|
+
//# sourceMappingURL=define-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-check.d.ts","sourceRoot":"","sources":["../src/define-check.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,kEAAkE;IAClE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,KAAK,CAAC,CAAC,SAAS,aAAa,GAAG,aAAa;IAC5D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,eAAe,EAAE,QAAQ,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,kFAAkF;IAClF,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,iCAAiC;IACjC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAAC;IACtC,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;CAC1E;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,aAAa;IACvD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,gDAAgD;IAChD,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACrB,mDAAmD;IACnD,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC;IAC3B,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;CAC1E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,WAAW,CAAC,KAAK,CAAC,CAAC,SAAS,aAAa,GAAG,EAAE,EAC5D,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,GACzB,KAAK,CAAC,CAAC,CAAC,CAcV"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// defineCheck — the factory plugin authors call to declare a check.
|
|
3
|
+
//
|
|
4
|
+
// Type inference flows from the `options` schema declared on the input
|
|
5
|
+
// to the `opts` argument of `run`. This is the surface that earns the
|
|
6
|
+
// SDK its right to exist — without it, plugin authors hand-write
|
|
7
|
+
// matching types twice.
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.defineCheck = defineCheck;
|
|
10
|
+
/**
|
|
11
|
+
* Author a cofferdam plugin check. The call site is the contract: the
|
|
12
|
+
* value passed in is the value the napi loader receives, with TS
|
|
13
|
+
* inference flowing from `options` into `run`'s third argument.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* import { defineCheck, Category, Severity } from "@cofferdam/check-sdk";
|
|
17
|
+
*
|
|
18
|
+
* export default defineCheck({
|
|
19
|
+
* id: "BrandCasing",
|
|
20
|
+
* category: Category.Warning,
|
|
21
|
+
* basePriority: 15,
|
|
22
|
+
* explanation: "Brand name must be all-caps in user-facing copy.",
|
|
23
|
+
* options: {
|
|
24
|
+
* brand: { default: "ROVIKORE", type: "string" },
|
|
25
|
+
* allowedAliases: { default: [] as string[], type: "string[]" },
|
|
26
|
+
* },
|
|
27
|
+
* run(file, ctx, opts) {
|
|
28
|
+
* for (const ln of file.lines()) {
|
|
29
|
+
* if (ln.isComment) continue;
|
|
30
|
+
* if (!ln.isStringLiteral) continue;
|
|
31
|
+
* const m = /\bRovikore\b/.exec(ln.text);
|
|
32
|
+
* if (!m) continue;
|
|
33
|
+
* if (opts.allowedAliases.some((a) => ln.text.includes(a))) continue;
|
|
34
|
+
* ctx.report({
|
|
35
|
+
* message: `Brand name must be "${opts.brand}", not "${m[0]}".`,
|
|
36
|
+
* span: ln.spanFor(m.index, m.index + m[0].length),
|
|
37
|
+
* });
|
|
38
|
+
* }
|
|
39
|
+
* },
|
|
40
|
+
* });
|
|
41
|
+
*/
|
|
42
|
+
function defineCheck(input) {
|
|
43
|
+
return {
|
|
44
|
+
id: input.id,
|
|
45
|
+
category: input.category,
|
|
46
|
+
basePriority: input.basePriority,
|
|
47
|
+
defaultSeverity: input.defaultSeverity ?? "medium",
|
|
48
|
+
explanation: input.explanation,
|
|
49
|
+
body: input.body,
|
|
50
|
+
requiresTypes: input.requiresTypes ?? false,
|
|
51
|
+
consistency: input.consistency ?? false,
|
|
52
|
+
options: input.options ?? {},
|
|
53
|
+
files: input.files,
|
|
54
|
+
run: input.run,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=define-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-check.js","sourceRoot":"","sources":["../src/define-check.ts"],"names":[],"mappings":";AAAA,oEAAoE;AACpE,EAAE;AACF,uEAAuE;AACvE,sEAAsE;AACtE,iEAAiE;AACjE,wBAAwB;;AA6GxB,kCAgBC;AAhDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,SAAgB,WAAW,CACzB,KAA0B;IAE1B,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,eAAe,EAAE,KAAK,CAAC,eAAe,IAAI,QAAQ;QAClD,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,aAAa,EAAE,KAAK,CAAC,aAAa,IAAI,KAAK;QAC3C,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,KAAK;QACvC,OAAO,EAAE,KAAK,CAAC,OAAO,IAAK,EAAQ;QACnC,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,GAAG,EAAE,KAAK,CAAC,GAAG;KACf,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { Category } from "./category.js";
|
|
2
|
+
export { Severity } from "./severity.js";
|
|
3
|
+
export { Walk } from "./ast.js";
|
|
4
|
+
export { defineCheck } from "./define-check.js";
|
|
5
|
+
export { runPlugin, buildSourceFile } from "./plugin-host.js";
|
|
6
|
+
export { loadPlugins, runPlugins } from "./loader.js";
|
|
7
|
+
export type { PluginReport, PluginRunInput, NativeLineView, } from "./plugin-host.js";
|
|
8
|
+
export type { LoadedPlugin, RunPluginsOptions } from "./loader.js";
|
|
9
|
+
export type { Check, DefineCheckInput, FileScope } from "./define-check.js";
|
|
10
|
+
export type { CheckContext, Fix, ReportArgs, SourceFile } from "./check-context.js";
|
|
11
|
+
export type { LineView } from "./line-view.js";
|
|
12
|
+
export type { Span, RelatedSpan } from "./span.js";
|
|
13
|
+
export type { AstView, AstVisitor, AstNode, AstNodeBase, ProgramNode, CallExpressionNode, ImportDeclarationNode, FunctionNode, ArrowFunctionExpressionNode, ClassNode, ObjectExpressionNode, MemberExpressionNode, IdentifierReferenceNode, NodeKind, NodeOfKind, } from "./ast.js";
|
|
14
|
+
export type { OptionKind, OptionSpec, OptionsSchema, ResolvedOptions, NoOptions, } from "./options.js";
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIhD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACtD,YAAY,EACV,YAAY,EACZ,cAAc,EACd,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEnE,YAAY,EAAE,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC5E,YAAY,EAAE,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACpF,YAAY,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,YAAY,EACV,OAAO,EACP,UAAU,EACV,OAAO,EACP,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,2BAA2B,EAC3B,SAAS,EACT,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACvB,QAAQ,EACR,UAAU,GACX,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,UAAU,EACV,UAAU,EACV,aAAa,EACb,eAAe,EACf,SAAS,GACV,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// @cofferdam/check-sdk — author cofferdam plugin checks in TypeScript.
|
|
3
|
+
//
|
|
4
|
+
// Plugin authors install this package, write a check with `defineCheck`,
|
|
5
|
+
// and `default export` it. The cofferdam napi loader (cd-81a.7) picks
|
|
6
|
+
// the module up via `cofferdam.toml`'s `plugins = [...]` array and runs
|
|
7
|
+
// it in a worker_thread per source file.
|
|
8
|
+
//
|
|
9
|
+
// This is the public surface. Everything exported here is part of the
|
|
10
|
+
// stability contract; everything kept internal is not. New exports are
|
|
11
|
+
// additive — removing or renaming an export is a breaking change.
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.runPlugins = exports.loadPlugins = exports.buildSourceFile = exports.runPlugin = exports.defineCheck = exports.Walk = exports.Severity = exports.Category = void 0;
|
|
14
|
+
var category_js_1 = require("./category.js");
|
|
15
|
+
Object.defineProperty(exports, "Category", { enumerable: true, get: function () { return category_js_1.Category; } });
|
|
16
|
+
var severity_js_1 = require("./severity.js");
|
|
17
|
+
Object.defineProperty(exports, "Severity", { enumerable: true, get: function () { return severity_js_1.Severity; } });
|
|
18
|
+
var ast_js_1 = require("./ast.js");
|
|
19
|
+
Object.defineProperty(exports, "Walk", { enumerable: true, get: function () { return ast_js_1.Walk; } });
|
|
20
|
+
var define_check_js_1 = require("./define-check.js");
|
|
21
|
+
Object.defineProperty(exports, "defineCheck", { enumerable: true, get: function () { return define_check_js_1.defineCheck; } });
|
|
22
|
+
// Loader runtime (cd-81a.7). Plugin authors import only the surfaces
|
|
23
|
+
// above; cofferdam's own JS wrapper is the consumer of these.
|
|
24
|
+
var plugin_host_js_1 = require("./plugin-host.js");
|
|
25
|
+
Object.defineProperty(exports, "runPlugin", { enumerable: true, get: function () { return plugin_host_js_1.runPlugin; } });
|
|
26
|
+
Object.defineProperty(exports, "buildSourceFile", { enumerable: true, get: function () { return plugin_host_js_1.buildSourceFile; } });
|
|
27
|
+
var loader_js_1 = require("./loader.js");
|
|
28
|
+
Object.defineProperty(exports, "loadPlugins", { enumerable: true, get: function () { return loader_js_1.loadPlugins; } });
|
|
29
|
+
Object.defineProperty(exports, "runPlugins", { enumerable: true, get: function () { return loader_js_1.runPlugins; } });
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,uEAAuE;AACvE,EAAE;AACF,yEAAyE;AACzE,sEAAsE;AACtE,wEAAwE;AACxE,yCAAyC;AACzC,EAAE;AACF,sEAAsE;AACtE,uEAAuE;AACvE,kEAAkE;;;AAElE,6CAAyC;AAAhC,uGAAA,QAAQ,OAAA;AACjB,6CAAyC;AAAhC,uGAAA,QAAQ,OAAA;AACjB,mCAAgC;AAAvB,8FAAA,IAAI,OAAA;AACb,qDAAgD;AAAvC,8GAAA,WAAW,OAAA;AAEpB,qEAAqE;AACrE,8DAA8D;AAC9D,mDAA8D;AAArD,2GAAA,SAAS,OAAA;AAAE,iHAAA,eAAe,OAAA;AACnC,yCAAsD;AAA7C,wGAAA,WAAW,OAAA;AAAE,uGAAA,UAAU,OAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Span } from "./span.js";
|
|
2
|
+
export interface LineView {
|
|
3
|
+
/** 1-based line number. */
|
|
4
|
+
readonly lineNo: number;
|
|
5
|
+
/** Line text with the trailing `\r` (CRLF) stripped, no `\n`. */
|
|
6
|
+
readonly text: string;
|
|
7
|
+
readonly isComment: boolean;
|
|
8
|
+
readonly isDocComment: boolean;
|
|
9
|
+
readonly isStringLiteral: boolean;
|
|
10
|
+
readonly isJsxText: boolean;
|
|
11
|
+
readonly isPragma: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Build a `Span` covering bytes `[charStart, charEnd)` *within this
|
|
14
|
+
* line*. `charStart`/`charEnd` are byte offsets relative to the start
|
|
15
|
+
* of `text` (after CRLF stripping). The returned span carries
|
|
16
|
+
* file-absolute `start_byte`/`end_byte` for direct use in
|
|
17
|
+
* `ctx.report({ span })`.
|
|
18
|
+
*
|
|
19
|
+
* Filed as cd-cgd to keep authoring concise — without this the check
|
|
20
|
+
* has to reconstruct the file-absolute offset by hand from the line's
|
|
21
|
+
* own start.
|
|
22
|
+
*/
|
|
23
|
+
spanFor(charStart: number, charEnd: number): Span;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=line-view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"line-view.d.ts","sourceRoot":"","sources":["../src/line-view.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,WAAW,QAAQ;IACvB,2BAA2B;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAE3B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACnD"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// LineView — plugin-facing view of a source line with classification
|
|
3
|
+
// flags populated by the engine from the parsed comment list and an AST
|
|
4
|
+
// walk over string/template literals. Mirrors
|
|
5
|
+
// cofferdam_core::lines::LineView.
|
|
6
|
+
//
|
|
7
|
+
// Flag semantics (kept in sync with cofferdam-core/src/lines.rs):
|
|
8
|
+
//
|
|
9
|
+
// - `isComment` — any comment (line `//`, single-line block, or
|
|
10
|
+
// multi-line block) overlaps this line.
|
|
11
|
+
// - `isDocComment` — a JSDoc-style block (`/** ... */`) overlaps. Implies
|
|
12
|
+
// `isComment`.
|
|
13
|
+
// - `isStringLiteral` — a `StringLiteral` or `TemplateLiteral` span
|
|
14
|
+
// overlaps this line.
|
|
15
|
+
// - `isJsxText` — JSX text content overlaps this line. Filed as cd-0ne;
|
|
16
|
+
// present in the SDK so plugins can target it as soon as the engine
|
|
17
|
+
// ships the flag.
|
|
18
|
+
// - `isPragma` — an annotation-style comment (`/* #__PURE__ */`,
|
|
19
|
+
// `/* @vite-ignore */`, etc.) overlaps. *Not* JSDoc.
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
//# sourceMappingURL=line-view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"line-view.js","sourceRoot":"","sources":["../src/line-view.ts"],"names":[],"mappings":";AAAA,qEAAqE;AACrE,wEAAwE;AACxE,8CAA8C;AAC9C,mCAAmC;AACnC,EAAE;AACF,kEAAkE;AAClE,EAAE;AACF,gEAAgE;AAChE,0CAA0C;AAC1C,0EAA0E;AAC1E,iBAAiB;AACjB,oEAAoE;AACpE,wBAAwB;AACxB,wEAAwE;AACxE,sEAAsE;AACtE,oBAAoB;AACpB,iEAAiE;AACjE,uDAAuD"}
|
package/dist/loader.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Check } from "./define-check.js";
|
|
2
|
+
import type { PluginReport, PluginRunInput } from "./plugin-host.js";
|
|
3
|
+
export interface LoadedPlugin {
|
|
4
|
+
/** Module path the plugin was loaded from. */
|
|
5
|
+
readonly path: string;
|
|
6
|
+
readonly check: Check;
|
|
7
|
+
}
|
|
8
|
+
export interface RunPluginsOptions {
|
|
9
|
+
/** Per-file timeout. Defaults to 5000ms. */
|
|
10
|
+
readonly timeoutMs?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Resolve and load a list of plugin module paths. Each path is
|
|
14
|
+
* `import()`'d; the module's default export must be the `Check` object
|
|
15
|
+
* returned from `defineCheck`.
|
|
16
|
+
*
|
|
17
|
+
* Throws on shape errors so the cofferdam binary fails loudly with a
|
|
18
|
+
* clear message — better than a runtime crash deep inside the loader.
|
|
19
|
+
*/
|
|
20
|
+
export declare function loadPlugins(paths: readonly string[]): Promise<LoadedPlugin[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Run every loaded plugin against every file. Collects `PluginReport[]`
|
|
23
|
+
* for the cofferdam binary to hand to native `mergePluginFindings`.
|
|
24
|
+
*
|
|
25
|
+
* In-process implementation: invokes plugins synchronously on the main
|
|
26
|
+
* thread. Worker-thread isolation lands in a follow-up bead — keeping
|
|
27
|
+
* the surface stable matters more than crash containment for the first
|
|
28
|
+
* milestone, since the SDK's e2e fixture (cd-7e4) is the immediate
|
|
29
|
+
* consumer and runs trusted code.
|
|
30
|
+
*/
|
|
31
|
+
export declare function runPlugins(plugins: readonly LoadedPlugin[], files: readonly PluginRunInput[], _options?: RunPluginsOptions): Promise<PluginReport[]>;
|
|
32
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAErE,MAAM,WAAW,YAAY;IAC3B,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,4CAA4C;IAC5C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAiBnF;AAaD;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,KAAK,EAAE,SAAS,cAAc,EAAE,EAChC,QAAQ,GAAE,iBAAsB,GAC/B,OAAO,CAAC,YAAY,EAAE,CAAC,CASzB"}
|
package/dist/loader.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Loader — orchestrates plugin discovery, worker_thread execution, and
|
|
3
|
+
// timeout enforcement. Used by the cofferdam binary's JS wrapper after
|
|
4
|
+
// it has the native `lineViews` helper available.
|
|
5
|
+
//
|
|
6
|
+
// API:
|
|
7
|
+
// const plugins = await loadPlugins(["./examples-plugins/brand-casing"]);
|
|
8
|
+
// const reports = await runPlugins(plugins, files, { timeoutMs: 5000 });
|
|
9
|
+
//
|
|
10
|
+
// `loadPlugins` resolves each path to its module's default export
|
|
11
|
+
// (expected to be a `Check` returned from `defineCheck`) and verifies
|
|
12
|
+
// shape. `runPlugins` spawns one worker_thread per plugin (NOT per
|
|
13
|
+
// file — workers are reused) and pushes file inputs through them.
|
|
14
|
+
//
|
|
15
|
+
// Crash containment + timeout: a plugin throwing or hanging on one
|
|
16
|
+
// file produces a `Warning.PluginCrashed` issue and the worker is
|
|
17
|
+
// recycled; analysis continues for remaining files.
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.loadPlugins = loadPlugins;
|
|
20
|
+
exports.runPlugins = runPlugins;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve and load a list of plugin module paths. Each path is
|
|
23
|
+
* `import()`'d; the module's default export must be the `Check` object
|
|
24
|
+
* returned from `defineCheck`.
|
|
25
|
+
*
|
|
26
|
+
* Throws on shape errors so the cofferdam binary fails loudly with a
|
|
27
|
+
* clear message — better than a runtime crash deep inside the loader.
|
|
28
|
+
*/
|
|
29
|
+
async function loadPlugins(paths) {
|
|
30
|
+
const { pathToFileURL } = await import("node:url");
|
|
31
|
+
const out = [];
|
|
32
|
+
for (const path of paths) {
|
|
33
|
+
// Convert OS paths to file:// URLs so dynamic import works on Windows
|
|
34
|
+
// (where C:\foo isn't a valid ESM specifier).
|
|
35
|
+
const specifier = /^([a-zA-Z]:|\/)/.test(path) ? pathToFileURL(path).href : path;
|
|
36
|
+
const mod = (await import(specifier));
|
|
37
|
+
const check = mod.default;
|
|
38
|
+
if (!isCheckShape(check)) {
|
|
39
|
+
throw new Error(`plugin at ${path} did not default-export a Check. Expected the value returned from defineCheck(...).`);
|
|
40
|
+
}
|
|
41
|
+
out.push({ path, check });
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
function isCheckShape(value) {
|
|
46
|
+
if (typeof value !== "object" || value === null)
|
|
47
|
+
return false;
|
|
48
|
+
const v = value;
|
|
49
|
+
return (typeof v.id === "string" &&
|
|
50
|
+
typeof v.category === "string" &&
|
|
51
|
+
typeof v.basePriority === "number" &&
|
|
52
|
+
typeof v.run === "function");
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Run every loaded plugin against every file. Collects `PluginReport[]`
|
|
56
|
+
* for the cofferdam binary to hand to native `mergePluginFindings`.
|
|
57
|
+
*
|
|
58
|
+
* In-process implementation: invokes plugins synchronously on the main
|
|
59
|
+
* thread. Worker-thread isolation lands in a follow-up bead — keeping
|
|
60
|
+
* the surface stable matters more than crash containment for the first
|
|
61
|
+
* milestone, since the SDK's e2e fixture (cd-7e4) is the immediate
|
|
62
|
+
* consumer and runs trusted code.
|
|
63
|
+
*/
|
|
64
|
+
async function runPlugins(plugins, files, _options = {}) {
|
|
65
|
+
const { runPlugin } = await import("./plugin-host.js");
|
|
66
|
+
const out = [];
|
|
67
|
+
for (const plugin of plugins) {
|
|
68
|
+
for (const file of files) {
|
|
69
|
+
out.push(...runPlugin(plugin.check, file));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":";AAAA,uEAAuE;AACvE,uEAAuE;AACvE,kDAAkD;AAClD,EAAE;AACF,OAAO;AACP,4EAA4E;AAC5E,2EAA2E;AAC3E,EAAE;AACF,kEAAkE;AAClE,sEAAsE;AACtE,mEAAmE;AACnE,kEAAkE;AAClE,EAAE;AACF,mEAAmE;AACnE,kEAAkE;AAClE,oDAAoD;;AAwBpD,kCAiBC;AAuBD,gCAaC;AA7DD;;;;;;;GAOG;AACI,KAAK,UAAU,WAAW,CAAC,KAAwB;IACxD,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IACnD,MAAM,GAAG,GAAmB,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,sEAAsE;QACtE,8CAA8C;QAC9C,MAAM,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACjF,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,CAA0B,CAAC;QAC/D,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC;QAC1B,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACb,aAAa,IAAI,qFAAqF,CACvG,CAAC;QACJ,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,CAAC,GAAG,KAAgC,CAAC;IAC3C,OAAO,CACL,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ;QACxB,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ;QAC9B,OAAO,CAAC,CAAC,YAAY,KAAK,QAAQ;QAClC,OAAO,CAAC,CAAC,GAAG,KAAK,UAAU,CAC5B,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACI,KAAK,UAAU,UAAU,CAC9B,OAAgC,EAChC,KAAgC,EAChC,WAA8B,EAAE;IAEhC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;IACvD,MAAM,GAAG,GAAmB,EAAE,CAAC;IAC/B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,GAAG,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export type OptionKind = "string" | "number" | "boolean" | "string[]" | "number[]";
|
|
2
|
+
export interface OptionSpec<K extends OptionKind, D> {
|
|
3
|
+
readonly type: K;
|
|
4
|
+
readonly default: D;
|
|
5
|
+
/** Optional human-readable description, surfaced by `cofferdam explain`. */
|
|
6
|
+
readonly description?: string;
|
|
7
|
+
}
|
|
8
|
+
type ResolvedFromKind<K extends OptionKind> = K extends "string" ? string : K extends "number" ? number : K extends "boolean" ? boolean : K extends "string[]" ? readonly string[] : K extends "number[]" ? readonly number[] : never;
|
|
9
|
+
/**
|
|
10
|
+
* The shape of `opts` inside a check's `run(file, ctx, opts)` callback —
|
|
11
|
+
* derived from the schema declared on `defineCheck.options`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* const sdk = defineCheck({
|
|
15
|
+
* options: {
|
|
16
|
+
* brand: { default: "ROVIKORE", type: "string" },
|
|
17
|
+
* allowedAliases: { default: [] as string[], type: "string[]" },
|
|
18
|
+
* },
|
|
19
|
+
* run(file, ctx, opts) {
|
|
20
|
+
* opts.brand; // string
|
|
21
|
+
* opts.allowedAliases; // readonly string[]
|
|
22
|
+
* },
|
|
23
|
+
* });
|
|
24
|
+
*/
|
|
25
|
+
export type ResolvedOptions<S> = {
|
|
26
|
+
readonly [K in keyof S]: S[K] extends OptionSpec<infer Kind, infer _D> ? ResolvedFromKind<Kind> : never;
|
|
27
|
+
};
|
|
28
|
+
/** A bare schema record — `Record<string, OptionSpec<...>>`. Constrained
|
|
29
|
+
* generics on `defineCheck` use this as the `extends` upper bound. */
|
|
30
|
+
export type OptionsSchema = Record<string, OptionSpec<OptionKind, unknown>>;
|
|
31
|
+
/** Empty schema — used as the default in `defineCheck` so the
|
|
32
|
+
* third `opts` argument is `Record<string, never>` for option-less
|
|
33
|
+
* checks rather than `undefined`. */
|
|
34
|
+
export declare const NO_OPTIONS: {};
|
|
35
|
+
export type NoOptions = typeof NO_OPTIONS;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;AAEnF,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,UAAU,EAAE,CAAC;IACjD,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAID,KAAK,gBAAgB,CAAC,CAAC,SAAS,UAAU,IAAI,CAAC,SAAS,QAAQ,GAC5D,MAAM,GACN,CAAC,SAAS,QAAQ,GAChB,MAAM,GACN,CAAC,SAAS,SAAS,GACjB,OAAO,GACP,CAAC,SAAS,UAAU,GAClB,SAAS,MAAM,EAAE,GACjB,CAAC,SAAS,UAAU,GAClB,SAAS,MAAM,EAAE,GACjB,KAAK,CAAC;AAElB;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI;IAC/B,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,UAAU,CAAC,MAAM,IAAI,EAAE,MAAM,EAAE,CAAC,GAClE,gBAAgB,CAAC,IAAI,CAAC,GACtB,KAAK;CACV,CAAC;AAEF;uEACuE;AACvE,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;AAE5E;;sCAEsC;AACtC,eAAO,MAAM,UAAU,IAAc,CAAC;AACtC,MAAM,MAAM,SAAS,GAAG,OAAO,UAAU,CAAC"}
|
package/dist/options.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Per-check options schema (cd-81a.3). Plugin authors declare an
|
|
3
|
+
// `options` block on their `defineCheck(...)` call; the engine validates
|
|
4
|
+
// user `cofferdam.toml` overrides against it at startup, and the resolved
|
|
5
|
+
// values are passed to `run(file, ctx, opts)` typed correctly.
|
|
6
|
+
//
|
|
7
|
+
// The schema is a record of name → { default, type }. The `type` field is
|
|
8
|
+
// the discriminator that drives both runtime validation and the type
|
|
9
|
+
// inference below.
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.NO_OPTIONS = void 0;
|
|
12
|
+
/** Empty schema — used as the default in `defineCheck` so the
|
|
13
|
+
* third `opts` argument is `Record<string, never>` for option-less
|
|
14
|
+
* checks rather than `undefined`. */
|
|
15
|
+
exports.NO_OPTIONS = {};
|
|
16
|
+
//# sourceMappingURL=options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":";AAAA,iEAAiE;AACjE,yEAAyE;AACzE,0EAA0E;AAC1E,+DAA+D;AAC/D,EAAE;AACF,0EAA0E;AAC1E,qEAAqE;AACrE,mBAAmB;;;AAmDnB;;sCAEsC;AACzB,QAAA,UAAU,GAAG,EAAW,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Check } from "./define-check.js";
|
|
2
|
+
import type { Fix } from "./check-context.js";
|
|
3
|
+
import type { LineView } from "./line-view.js";
|
|
4
|
+
import type { Span } from "./span.js";
|
|
5
|
+
export interface NativeLineView {
|
|
6
|
+
readonly lineNo: number;
|
|
7
|
+
readonly text: string;
|
|
8
|
+
readonly isComment: boolean;
|
|
9
|
+
readonly isDocComment: boolean;
|
|
10
|
+
readonly isStringLiteral: boolean;
|
|
11
|
+
readonly isJsxText: boolean;
|
|
12
|
+
readonly isPragma: boolean;
|
|
13
|
+
readonly lineStart: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* One report that crosses the worker_thread boundary back to the
|
|
17
|
+
* loader. Mirrors the napi `JsReport` struct in cofferdam-napi.
|
|
18
|
+
*/
|
|
19
|
+
export interface PluginReport {
|
|
20
|
+
readonly checkId: string;
|
|
21
|
+
readonly message: string;
|
|
22
|
+
readonly file: string;
|
|
23
|
+
readonly startByte: number;
|
|
24
|
+
readonly endByte: number;
|
|
25
|
+
readonly severity: string;
|
|
26
|
+
readonly fix?: Fix;
|
|
27
|
+
readonly related?: readonly {
|
|
28
|
+
readonly file: string;
|
|
29
|
+
readonly span: Span;
|
|
30
|
+
}[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Runtime input passed from the loader to a plugin's `run()` callback.
|
|
34
|
+
* Built from native `lineViews()` + the file path/text. Cheap to
|
|
35
|
+
* serialise (no AST handles cross the boundary).
|
|
36
|
+
*/
|
|
37
|
+
export interface PluginRunInput {
|
|
38
|
+
readonly path: string;
|
|
39
|
+
readonly text: string;
|
|
40
|
+
readonly lineViews: readonly NativeLineView[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Build the `SourceFile` shape a plugin's `run()` callback expects.
|
|
44
|
+
* `ast` is `null` here — AST access lives behind a separate napi call
|
|
45
|
+
* the loader can route through worker_threads in a follow-up bead. The
|
|
46
|
+
* line-walk Pattern A checks (BrandCasing) work today.
|
|
47
|
+
*/
|
|
48
|
+
export declare function buildSourceFile(input: PluginRunInput): {
|
|
49
|
+
path: string;
|
|
50
|
+
text: string;
|
|
51
|
+
lines(): IterableIterator<LineView>;
|
|
52
|
+
ast: null;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Execute a single plugin against a single file. Collects `ctx.report`
|
|
56
|
+
* calls into a `PluginReport[]` the loader can hand to native
|
|
57
|
+
* `mergePluginFindings`.
|
|
58
|
+
*
|
|
59
|
+
* This is the function a worker_thread invokes. The host process never
|
|
60
|
+
* touches plugin code directly — crash containment is the worker's
|
|
61
|
+
* boundary.
|
|
62
|
+
*/
|
|
63
|
+
export declare function runPlugin(check: Check, input: PluginRunInput): PluginReport[];
|
|
64
|
+
//# sourceMappingURL=plugin-host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-host.d.ts","sourceRoot":"","sources":["../src/plugin-host.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAgB,GAAG,EAAc,MAAM,oBAAoB,CAAC;AACxE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAItC,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IACnB,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;KAAE,EAAE,CAAC;CAC9E;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;CAC/C;AAwBD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc;;;aAKxC,gBAAgB,CAAC,QAAQ,CAAC;;EAqBtC;AAID;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,GAAG,YAAY,EAAE,CA0C7E"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Plugin host runtime — the JS side of cd-81a.7.
|
|
3
|
+
//
|
|
4
|
+
// Lives in @cofferdam/check-sdk so the loader and the authoring SDK
|
|
5
|
+
// share one published surface. The cofferdam binary's JS wrapper (in
|
|
6
|
+
// packages/cofferdam) imports `loadPlugin` and `runPlugin` from here
|
|
7
|
+
// after it has obtained the native addon's `lineViews` /
|
|
8
|
+
// `mergePluginFindings` helpers.
|
|
9
|
+
//
|
|
10
|
+
// Why worker_threads: a plugin throwing on one file must not crash the
|
|
11
|
+
// engine driver, and unbounded plugin runs must be timeout-able.
|
|
12
|
+
// worker_threads gives crash containment + per-message timeout for free,
|
|
13
|
+
// at the cost of postMessage serialisation per file (cheap relative to
|
|
14
|
+
// parsing).
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.buildSourceFile = buildSourceFile;
|
|
17
|
+
exports.runPlugin = runPlugin;
|
|
18
|
+
// ---- runtime construction --------------------------------------------
|
|
19
|
+
function buildLineView(native) {
|
|
20
|
+
return {
|
|
21
|
+
lineNo: native.lineNo,
|
|
22
|
+
text: native.text,
|
|
23
|
+
isComment: native.isComment,
|
|
24
|
+
isDocComment: native.isDocComment,
|
|
25
|
+
isStringLiteral: native.isStringLiteral,
|
|
26
|
+
isJsxText: native.isJsxText,
|
|
27
|
+
isPragma: native.isPragma,
|
|
28
|
+
spanFor(charStart, charEnd) {
|
|
29
|
+
return {
|
|
30
|
+
line: native.lineNo,
|
|
31
|
+
column: charStart + 1,
|
|
32
|
+
start_byte: native.lineStart + charStart,
|
|
33
|
+
end_byte: native.lineStart + charEnd,
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Build the `SourceFile` shape a plugin's `run()` callback expects.
|
|
40
|
+
* `ast` is `null` here — AST access lives behind a separate napi call
|
|
41
|
+
* the loader can route through worker_threads in a follow-up bead. The
|
|
42
|
+
* line-walk Pattern A checks (BrandCasing) work today.
|
|
43
|
+
*/
|
|
44
|
+
function buildSourceFile(input) {
|
|
45
|
+
const lineViews = input.lineViews.map(buildLineView);
|
|
46
|
+
return {
|
|
47
|
+
path: input.path,
|
|
48
|
+
text: input.text,
|
|
49
|
+
lines() {
|
|
50
|
+
let i = 0;
|
|
51
|
+
const it = {
|
|
52
|
+
next() {
|
|
53
|
+
if (i < lineViews.length) {
|
|
54
|
+
return { value: lineViews[i++], done: false };
|
|
55
|
+
}
|
|
56
|
+
return { value: undefined, done: true };
|
|
57
|
+
},
|
|
58
|
+
[Symbol.iterator]() {
|
|
59
|
+
return it;
|
|
60
|
+
},
|
|
61
|
+
return(value) {
|
|
62
|
+
i = lineViews.length;
|
|
63
|
+
return { value: value, done: true };
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
return it;
|
|
67
|
+
},
|
|
68
|
+
ast: null,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// ---- runPlugin -------------------------------------------------------
|
|
72
|
+
/**
|
|
73
|
+
* Execute a single plugin against a single file. Collects `ctx.report`
|
|
74
|
+
* calls into a `PluginReport[]` the loader can hand to native
|
|
75
|
+
* `mergePluginFindings`.
|
|
76
|
+
*
|
|
77
|
+
* This is the function a worker_thread invokes. The host process never
|
|
78
|
+
* touches plugin code directly — crash containment is the worker's
|
|
79
|
+
* boundary.
|
|
80
|
+
*/
|
|
81
|
+
function runPlugin(check, input) {
|
|
82
|
+
const reports = [];
|
|
83
|
+
const ctx = {
|
|
84
|
+
report(args) {
|
|
85
|
+
const { span, severity, related, fix } = args;
|
|
86
|
+
const report = {
|
|
87
|
+
checkId: check.id,
|
|
88
|
+
message: args.message,
|
|
89
|
+
file: input.path,
|
|
90
|
+
startByte: span.start_byte,
|
|
91
|
+
endByte: span.end_byte,
|
|
92
|
+
severity: severity ?? check.defaultSeverity,
|
|
93
|
+
...(fix !== undefined ? { fix } : {}),
|
|
94
|
+
...(related !== undefined ? { related } : {}),
|
|
95
|
+
};
|
|
96
|
+
reports.push(report);
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
// Resolve options — currently use the schema defaults; the loader can
|
|
100
|
+
// pass user-supplied overrides through cofferdam.toml in a follow-up.
|
|
101
|
+
// The cast is sound because the schema's defaults already satisfy
|
|
102
|
+
// ResolvedOptions<S>'s mapped types by construction.
|
|
103
|
+
const opts = resolveDefaults(check.options);
|
|
104
|
+
try {
|
|
105
|
+
check.run(buildSourceFile(input), ctx, opts);
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
// Don't swallow the plugin error — push a synthetic report so the
|
|
109
|
+
// engine surfaces it as `Warning.PluginCrashed` and analysis
|
|
110
|
+
// continues for the rest of the corpus.
|
|
111
|
+
reports.push({
|
|
112
|
+
checkId: "Warning.PluginCrashed",
|
|
113
|
+
message: `plugin '${check.id}' threw: ${err instanceof Error ? err.message : String(err)}`,
|
|
114
|
+
file: input.path,
|
|
115
|
+
startByte: 0,
|
|
116
|
+
endByte: 0,
|
|
117
|
+
severity: "high",
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return reports;
|
|
121
|
+
}
|
|
122
|
+
function resolveDefaults(schema) {
|
|
123
|
+
const out = {};
|
|
124
|
+
for (const key of Object.keys(schema)) {
|
|
125
|
+
out[key] = schema[key].default;
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=plugin-host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-host.js","sourceRoot":"","sources":["../src/plugin-host.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const Severity: {
|
|
2
|
+
readonly Info: "info";
|
|
3
|
+
readonly Low: "low";
|
|
4
|
+
readonly Medium: "medium";
|
|
5
|
+
readonly High: "high";
|
|
6
|
+
readonly Critical: "critical";
|
|
7
|
+
};
|
|
8
|
+
export type Severity = (typeof Severity)[keyof typeof Severity];
|
|
9
|
+
//# sourceMappingURL=severity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"severity.d.ts","sourceRoot":"","sources":["../src/severity.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,QAAQ;;;;;;CAMX,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC"}
|
package/dist/severity.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Mirror of cofferdam_core::Severity. Wire form is the lowercase string;
|
|
3
|
+
// the const-as-namespace pattern keeps `Severity.Warning` ergonomic
|
|
4
|
+
// without spinning up an enum (which TS enums emit runtime code for).
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Severity = void 0;
|
|
7
|
+
exports.Severity = {
|
|
8
|
+
Info: "info",
|
|
9
|
+
Low: "low",
|
|
10
|
+
Medium: "medium",
|
|
11
|
+
High: "high",
|
|
12
|
+
Critical: "critical",
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=severity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"severity.js","sourceRoot":"","sources":["../src/severity.ts"],"names":[],"mappings":";AAAA,yEAAyE;AACzE,oEAAoE;AACpE,sEAAsE;;;AAEzD,QAAA,QAAQ,GAAG;IACtB,IAAI,EAAE,MAAM;IACZ,GAAG,EAAE,KAAK;IACV,MAAM,EAAE,QAAQ;IAChB,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,UAAU;CACZ,CAAC"}
|
package/dist/span.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface Span {
|
|
2
|
+
/** 1-based line number. */
|
|
3
|
+
readonly line: number;
|
|
4
|
+
/** 1-based column number, in UTF-8 bytes from the start of the line. */
|
|
5
|
+
readonly column: number;
|
|
6
|
+
/** 0-based byte offset from the start of the file (inclusive). */
|
|
7
|
+
readonly start_byte: number;
|
|
8
|
+
/** 0-based byte offset from the start of the file (exclusive). */
|
|
9
|
+
readonly end_byte: number;
|
|
10
|
+
}
|
|
11
|
+
export interface RelatedSpan {
|
|
12
|
+
readonly file: string;
|
|
13
|
+
readonly span: Span;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=span.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"span.d.ts","sourceRoot":"","sources":["../src/span.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,IAAI;IACnB,2BAA2B;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;CACrB"}
|
package/dist/span.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Mirror of cofferdam_core::Span. Carries both human (line/column) and
|
|
3
|
+
// machine (byte offsets) coordinates so `ctx.report` consumers can do
|
|
4
|
+
// either without re-parsing.
|
|
5
|
+
//
|
|
6
|
+
// All coordinates are 1-based for line, 1-based for column, 0-based for
|
|
7
|
+
// bytes — matching the Rust struct and the JSON formatter contract.
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
//# sourceMappingURL=span.js.map
|
package/dist/span.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"span.js","sourceRoot":"","sources":["../src/span.ts"],"names":[],"mappings":";AAAA,uEAAuE;AACvE,sEAAsE;AACtE,6BAA6B;AAC7B,EAAE;AACF,wEAAwE;AACxE,oEAAoE"}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cofferdam/check-sdk",
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "Author cofferdam plugin checks in TypeScript. defineCheck factory + types.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/TAJD/cofferdam.git",
|
|
9
|
+
"directory": "packages/check-sdk"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://tajd.github.io/cofferdam",
|
|
12
|
+
"bugs": "https://github.com/TAJD/cofferdam/issues",
|
|
13
|
+
"main": "dist/index.js",
|
|
14
|
+
"types": "dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"keywords": [
|
|
27
|
+
"cofferdam",
|
|
28
|
+
"linter",
|
|
29
|
+
"static-analysis",
|
|
30
|
+
"plugin-sdk",
|
|
31
|
+
"typescript"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc -p .",
|
|
35
|
+
"typecheck": "tsc -p . --noEmit",
|
|
36
|
+
"test:types": "tsc -p tests"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=16"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^20",
|
|
43
|
+
"typescript": "^5.6.0"
|
|
44
|
+
}
|
|
45
|
+
}
|