@specferret/core 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -62
- package/dist/context/index.d.ts +5 -1
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +47 -1
- package/dist/context/index.js.map +1 -1
- package/dist/extractor/__fixtures__/typescript/generics.d.ts +6 -0
- package/dist/extractor/__fixtures__/typescript/generics.d.ts.map +1 -0
- package/dist/extractor/__fixtures__/typescript/generics.js +2 -0
- package/dist/extractor/__fixtures__/typescript/generics.js.map +1 -0
- package/dist/extractor/__fixtures__/typescript/intersections.d.ts +6 -0
- package/dist/extractor/__fixtures__/typescript/intersections.d.ts.map +1 -0
- package/dist/extractor/__fixtures__/typescript/intersections.js +2 -0
- package/dist/extractor/__fixtures__/typescript/intersections.js.map +1 -0
- package/dist/extractor/__fixtures__/typescript/optional-nested.d.ts +8 -0
- package/dist/extractor/__fixtures__/typescript/optional-nested.d.ts.map +1 -0
- package/dist/extractor/__fixtures__/typescript/optional-nested.js +2 -0
- package/dist/extractor/__fixtures__/typescript/optional-nested.js.map +1 -0
- package/dist/extractor/__fixtures__/typescript/unions.d.ts +5 -0
- package/dist/extractor/__fixtures__/typescript/unions.d.ts.map +1 -0
- package/dist/extractor/__fixtures__/typescript/unions.js +2 -0
- package/dist/extractor/__fixtures__/typescript/unions.js.map +1 -0
- package/dist/extractor/__fixtures__/typescript/unsupported-syntax.d.ts +7 -0
- package/dist/extractor/__fixtures__/typescript/unsupported-syntax.d.ts.map +1 -0
- package/dist/extractor/__fixtures__/typescript/unsupported-syntax.js +2 -0
- package/dist/extractor/__fixtures__/typescript/unsupported-syntax.js.map +1 -0
- package/dist/extractor/contract-types.d.ts +5 -0
- package/dist/extractor/contract-types.d.ts.map +1 -0
- package/dist/extractor/contract-types.js +8 -0
- package/dist/extractor/contract-types.js.map +1 -0
- package/dist/extractor/frontmatter.d.ts +6 -1
- package/dist/extractor/frontmatter.d.ts.map +1 -1
- package/dist/extractor/frontmatter.js +17 -6
- package/dist/extractor/frontmatter.js.map +1 -1
- package/dist/extractor/typescript.d.ts +6 -1
- package/dist/extractor/typescript.d.ts.map +1 -1
- package/dist/extractor/typescript.js +403 -185
- package/dist/extractor/typescript.js.map +1 -1
- package/dist/extractor/upward-classifier.d.ts +25 -0
- package/dist/extractor/upward-classifier.d.ts.map +1 -0
- package/dist/extractor/upward-classifier.js +48 -0
- package/dist/extractor/upward-classifier.js.map +1 -0
- package/dist/extractor/validator.d.ts +9 -0
- package/dist/extractor/validator.d.ts.map +1 -1
- package/dist/extractor/validator.js +28 -9
- package/dist/extractor/validator.js.map +1 -1
- package/dist/index.d.ts +14 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -12
- package/dist/index.js.map +1 -1
- package/dist/reconciler/index.d.ts +10 -0
- package/dist/reconciler/index.d.ts.map +1 -1
- package/dist/reconciler/index.js +76 -0
- package/dist/reconciler/index.js.map +1 -1
- package/dist/store/sqlite.d.ts +1 -1
- package/dist/store/sqlite.d.ts.map +1 -1
- package/dist/store/sqlite.js +106 -101
- package/dist/store/sqlite.js.map +1 -1
- package/dist/store/types.d.ts +6 -2
- package/dist/store/types.d.ts.map +1 -1
- package/package.json +47 -44
- package/src/config.ts +48 -0
- package/src/context/index.test.ts +274 -0
- package/src/context/index.ts +178 -0
- package/src/extractor/__fixtures__/typescript/generics.golden.json +36 -0
- package/src/extractor/__fixtures__/typescript/generics.ts +5 -0
- package/src/extractor/__fixtures__/typescript/intersections.golden.json +18 -0
- package/src/extractor/__fixtures__/typescript/intersections.ts +5 -0
- package/src/extractor/__fixtures__/typescript/optional-nested.golden.json +41 -0
- package/src/extractor/__fixtures__/typescript/optional-nested.ts +7 -0
- package/src/extractor/__fixtures__/typescript/unions.golden.json +30 -0
- package/src/extractor/__fixtures__/typescript/unions.ts +4 -0
- package/src/extractor/__fixtures__/typescript/unsupported-syntax.golden.json +20 -0
- package/src/extractor/__fixtures__/typescript/unsupported-syntax.ts +6 -0
- package/src/extractor/contract-types.ts +11 -0
- package/src/extractor/frontmatter.test.ts +291 -0
- package/src/extractor/frontmatter.ts +87 -0
- package/src/extractor/hash.ts +26 -0
- package/src/extractor/typescript.test.ts +339 -0
- package/src/extractor/typescript.ts +597 -0
- package/src/extractor/upward-classifier.test.ts +188 -0
- package/src/extractor/upward-classifier.ts +68 -0
- package/src/extractor/validator.test.ts +228 -0
- package/src/extractor/validator.ts +199 -0
- package/src/index.ts +17 -0
- package/src/reconciler/import-suggestions.test.ts +101 -0
- package/src/reconciler/import-suggestions.ts +157 -0
- package/src/reconciler/index.test.ts +248 -0
- package/src/reconciler/index.ts +445 -0
- package/src/store/factory.ts +54 -0
- package/src/store/postgres.ts +84 -0
- package/src/store/sqlite.test.ts +328 -0
- package/src/store/sqlite.ts +231 -0
- package/src/store/types.ts +101 -0
- package/src/utils/paths.ts +24 -0
package/dist/store/sqlite.js
CHANGED
|
@@ -1,85 +1,88 @@
|
|
|
1
|
-
import { Database } from
|
|
2
|
-
import * as path from
|
|
3
|
-
import * as fs from
|
|
4
|
-
import { randomUUID } from
|
|
5
|
-
import { findProjectRoot } from
|
|
1
|
+
import { Database } from 'bun:sqlite';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import * as fs from 'node:fs';
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
5
|
+
import { findProjectRoot } from '../utils/paths.js';
|
|
6
6
|
export class SqliteStore {
|
|
7
7
|
db = null;
|
|
8
8
|
dbPath;
|
|
9
9
|
constructor(customPath) {
|
|
10
10
|
const root = findProjectRoot();
|
|
11
|
-
const defaultPath = path.join(root,
|
|
12
|
-
this.dbPath =
|
|
13
|
-
customPath === ":memory:"
|
|
14
|
-
? ":memory:"
|
|
15
|
-
: customPath
|
|
16
|
-
? path.resolve(root, customPath)
|
|
17
|
-
: defaultPath;
|
|
11
|
+
const defaultPath = path.join(root, '.ferret', 'graph.db');
|
|
12
|
+
this.dbPath = customPath === ':memory:' ? ':memory:' : customPath ? path.resolve(root, customPath) : defaultPath;
|
|
18
13
|
}
|
|
19
14
|
async init() {
|
|
20
15
|
if (this.db)
|
|
21
16
|
return;
|
|
22
|
-
if (this.dbPath !==
|
|
17
|
+
if (this.dbPath !== ':memory:') {
|
|
23
18
|
const ferretDir = path.dirname(this.dbPath);
|
|
24
19
|
if (!fs.existsSync(ferretDir)) {
|
|
25
20
|
fs.mkdirSync(ferretDir, { recursive: true });
|
|
26
21
|
}
|
|
27
|
-
const gitignorePath = path.join(ferretDir,
|
|
22
|
+
const gitignorePath = path.join(ferretDir, '.gitignore');
|
|
28
23
|
try {
|
|
29
|
-
fs.writeFileSync(gitignorePath,
|
|
24
|
+
fs.writeFileSync(gitignorePath, '*\n!.gitignore\n!context.json\n', 'utf-8');
|
|
30
25
|
}
|
|
31
26
|
catch { }
|
|
32
27
|
}
|
|
33
28
|
this.db = new Database(this.dbPath);
|
|
34
|
-
this.db.exec(
|
|
35
|
-
this.db.exec(
|
|
36
|
-
this.db.exec(`
|
|
37
|
-
CREATE TABLE IF NOT EXISTS ferret_nodes (
|
|
38
|
-
id TEXT PRIMARY KEY,
|
|
39
|
-
file_path TEXT NOT NULL,
|
|
40
|
-
hash TEXT NOT NULL,
|
|
41
|
-
status TEXT NOT NULL,
|
|
42
|
-
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
CREATE TABLE IF NOT EXISTS ferret_contracts (
|
|
46
|
-
id TEXT PRIMARY KEY,
|
|
47
|
-
node_id TEXT NOT NULL,
|
|
48
|
-
shape_hash TEXT NOT NULL,
|
|
49
|
-
shape_schema TEXT NOT NULL DEFAULT '{}',
|
|
50
|
-
type TEXT NOT NULL,
|
|
51
|
-
status TEXT NOT NULL,
|
|
52
|
-
FOREIGN KEY (node_id) REFERENCES ferret_nodes(id)
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
CREATE TABLE IF NOT EXISTS ferret_dependencies (
|
|
56
|
-
id TEXT PRIMARY KEY,
|
|
57
|
-
source_node_id TEXT NOT NULL,
|
|
58
|
-
target_contract_id TEXT NOT NULL,
|
|
59
|
-
FOREIGN KEY (source_node_id) REFERENCES ferret_nodes(id)
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
CREATE TABLE IF NOT EXISTS ferret_reconciliation_log (
|
|
63
|
-
id TEXT PRIMARY KEY,
|
|
64
|
-
node_id TEXT NOT NULL,
|
|
65
|
-
triggered_by TEXT NOT NULL,
|
|
66
|
-
resolved_by TEXT,
|
|
67
|
-
resolution_notes TEXT,
|
|
68
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
CREATE TABLE IF NOT EXISTS ferret_placement_decisions (
|
|
72
|
-
id TEXT PRIMARY KEY,
|
|
73
|
-
node_id TEXT NOT NULL,
|
|
74
|
-
placed_by TEXT NOT NULL,
|
|
75
|
-
reasoning TEXT,
|
|
76
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
77
|
-
);
|
|
29
|
+
this.db.exec('PRAGMA journal_mode = WAL;');
|
|
30
|
+
this.db.exec('PRAGMA foreign_keys = ON;');
|
|
31
|
+
this.db.exec(`
|
|
32
|
+
CREATE TABLE IF NOT EXISTS ferret_nodes (
|
|
33
|
+
id TEXT PRIMARY KEY,
|
|
34
|
+
file_path TEXT NOT NULL,
|
|
35
|
+
hash TEXT NOT NULL,
|
|
36
|
+
status TEXT NOT NULL,
|
|
37
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
CREATE TABLE IF NOT EXISTS ferret_contracts (
|
|
41
|
+
id TEXT PRIMARY KEY,
|
|
42
|
+
node_id TEXT NOT NULL,
|
|
43
|
+
shape_hash TEXT NOT NULL,
|
|
44
|
+
shape_schema TEXT NOT NULL DEFAULT '{}',
|
|
45
|
+
type TEXT NOT NULL,
|
|
46
|
+
status TEXT NOT NULL,
|
|
47
|
+
FOREIGN KEY (node_id) REFERENCES ferret_nodes(id)
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
CREATE TABLE IF NOT EXISTS ferret_dependencies (
|
|
51
|
+
id TEXT PRIMARY KEY,
|
|
52
|
+
source_node_id TEXT NOT NULL,
|
|
53
|
+
target_contract_id TEXT NOT NULL,
|
|
54
|
+
FOREIGN KEY (source_node_id) REFERENCES ferret_nodes(id)
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
CREATE TABLE IF NOT EXISTS ferret_reconciliation_log (
|
|
58
|
+
id TEXT PRIMARY KEY,
|
|
59
|
+
node_id TEXT NOT NULL,
|
|
60
|
+
triggered_by TEXT NOT NULL,
|
|
61
|
+
resolved_by TEXT,
|
|
62
|
+
resolution_notes TEXT,
|
|
63
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
CREATE TABLE IF NOT EXISTS ferret_placement_decisions (
|
|
67
|
+
id TEXT PRIMARY KEY,
|
|
68
|
+
node_id TEXT NOT NULL,
|
|
69
|
+
placed_by TEXT NOT NULL,
|
|
70
|
+
reasoning TEXT,
|
|
71
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
72
|
+
);
|
|
78
73
|
`);
|
|
79
74
|
try {
|
|
80
75
|
this.db.exec(`ALTER TABLE ferret_contracts ADD COLUMN shape_schema TEXT NOT NULL DEFAULT '{}';`);
|
|
81
76
|
}
|
|
82
77
|
catch { }
|
|
78
|
+
try {
|
|
79
|
+
this.db.exec(`ALTER TABLE ferret_contracts ADD COLUMN code_source_file TEXT;`);
|
|
80
|
+
}
|
|
81
|
+
catch { }
|
|
82
|
+
try {
|
|
83
|
+
this.db.exec(`ALTER TABLE ferret_contracts ADD COLUMN code_source_symbol TEXT;`);
|
|
84
|
+
}
|
|
85
|
+
catch { }
|
|
83
86
|
}
|
|
84
87
|
async close() {
|
|
85
88
|
if (this.db) {
|
|
@@ -88,48 +91,50 @@ export class SqliteStore {
|
|
|
88
91
|
}
|
|
89
92
|
}
|
|
90
93
|
async getNodeByFilePath(filePath) {
|
|
91
|
-
const row = this.db.prepare(
|
|
94
|
+
const row = this.db.prepare('SELECT * FROM ferret_nodes WHERE file_path = ?').get(filePath);
|
|
92
95
|
return row ?? null;
|
|
93
96
|
}
|
|
94
97
|
async upsertNode(node) {
|
|
95
|
-
this.db.prepare(`
|
|
96
|
-
INSERT INTO ferret_nodes (id, file_path, hash, status)
|
|
97
|
-
VALUES (?, ?, ?, ?)
|
|
98
|
-
ON CONFLICT(id) DO UPDATE SET
|
|
99
|
-
file_path = excluded.file_path,
|
|
100
|
-
hash = excluded.hash,
|
|
101
|
-
status = excluded.status,
|
|
102
|
-
updated_at = CURRENT_TIMESTAMP
|
|
98
|
+
this.db.prepare(`
|
|
99
|
+
INSERT INTO ferret_nodes (id, file_path, hash, status)
|
|
100
|
+
VALUES (?, ?, ?, ?)
|
|
101
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
102
|
+
file_path = excluded.file_path,
|
|
103
|
+
hash = excluded.hash,
|
|
104
|
+
status = excluded.status,
|
|
105
|
+
updated_at = CURRENT_TIMESTAMP
|
|
103
106
|
`).run(node.id, node.file_path, node.hash, node.status);
|
|
104
107
|
}
|
|
105
108
|
async getAllContractIds() {
|
|
106
|
-
return this.db.prepare(
|
|
109
|
+
return this.db.prepare('SELECT id FROM ferret_contracts').all().map((r) => r.id);
|
|
107
110
|
}
|
|
108
111
|
async upsertContract(contract) {
|
|
109
|
-
this.db.prepare(`
|
|
110
|
-
INSERT INTO ferret_contracts (id, node_id, shape_hash, shape_schema, type, status)
|
|
111
|
-
VALUES (?, ?, ?, ?, ?, ?)
|
|
112
|
-
ON CONFLICT(id) DO UPDATE SET
|
|
113
|
-
node_id = excluded.node_id,
|
|
114
|
-
shape_hash = excluded.shape_hash,
|
|
115
|
-
shape_schema = excluded.shape_schema,
|
|
116
|
-
type = excluded.type,
|
|
117
|
-
status = excluded.status
|
|
118
|
-
|
|
112
|
+
this.db.prepare(`
|
|
113
|
+
INSERT INTO ferret_contracts (id, node_id, shape_hash, shape_schema, type, status, code_source_file, code_source_symbol)
|
|
114
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
115
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
116
|
+
node_id = excluded.node_id,
|
|
117
|
+
shape_hash = excluded.shape_hash,
|
|
118
|
+
shape_schema = excluded.shape_schema,
|
|
119
|
+
type = excluded.type,
|
|
120
|
+
status = excluded.status,
|
|
121
|
+
code_source_file = excluded.code_source_file,
|
|
122
|
+
code_source_symbol = excluded.code_source_symbol
|
|
123
|
+
`).run(contract.id, contract.node_id, contract.shape_hash, contract.shape_schema, contract.type, contract.status, contract.code_source_file ?? null, contract.code_source_symbol ?? null);
|
|
119
124
|
}
|
|
120
125
|
async upsertDependency(dependency) {
|
|
121
|
-
this.db.prepare(`
|
|
122
|
-
INSERT INTO ferret_dependencies (id, source_node_id, target_contract_id)
|
|
123
|
-
VALUES (?, ?, ?)
|
|
124
|
-
ON CONFLICT(id) DO NOTHING
|
|
126
|
+
this.db.prepare(`
|
|
127
|
+
INSERT INTO ferret_dependencies (id, source_node_id, target_contract_id)
|
|
128
|
+
VALUES (?, ?, ?)
|
|
129
|
+
ON CONFLICT(id) DO NOTHING
|
|
125
130
|
`).run(dependency.id, dependency.source_node_id, dependency.target_contract_id);
|
|
126
131
|
}
|
|
127
132
|
async replaceDependenciesForSourceNode(sourceNodeId, targetContractIds) {
|
|
128
133
|
const uniqueTargets = [...new Set(targetContractIds)].sort();
|
|
129
|
-
const deleteStatement = this.db.prepare(
|
|
130
|
-
const insertStatement = this.db.prepare(`
|
|
131
|
-
INSERT INTO ferret_dependencies (id, source_node_id, target_contract_id)
|
|
132
|
-
VALUES (?, ?, ?)
|
|
134
|
+
const deleteStatement = this.db.prepare('DELETE FROM ferret_dependencies WHERE source_node_id = ?');
|
|
135
|
+
const insertStatement = this.db.prepare(`
|
|
136
|
+
INSERT INTO ferret_dependencies (id, source_node_id, target_contract_id)
|
|
137
|
+
VALUES (?, ?, ?)
|
|
133
138
|
`);
|
|
134
139
|
const transaction = this.db.transaction((sourceId) => {
|
|
135
140
|
deleteStatement.run(sourceId);
|
|
@@ -140,41 +145,41 @@ export class SqliteStore {
|
|
|
140
145
|
transaction(sourceNodeId);
|
|
141
146
|
}
|
|
142
147
|
async getNodes() {
|
|
143
|
-
return this.db.prepare(
|
|
148
|
+
return this.db.prepare('SELECT * FROM ferret_nodes').all();
|
|
144
149
|
}
|
|
145
150
|
async getNodesByStatus(status) {
|
|
146
|
-
return this.db.prepare(
|
|
151
|
+
return this.db.prepare('SELECT * FROM ferret_nodes WHERE status = ?').all(status);
|
|
147
152
|
}
|
|
148
153
|
async getContracts() {
|
|
149
|
-
return this.db.prepare(
|
|
154
|
+
return this.db.prepare('SELECT * FROM ferret_contracts').all();
|
|
150
155
|
}
|
|
151
156
|
async getContract(id) {
|
|
152
|
-
const row = this.db.prepare(
|
|
157
|
+
const row = this.db.prepare('SELECT * FROM ferret_contracts WHERE id = ?').get(id);
|
|
153
158
|
return row ?? null;
|
|
154
159
|
}
|
|
155
160
|
async getDependencies() {
|
|
156
|
-
return this.db.prepare(
|
|
161
|
+
return this.db.prepare('SELECT * FROM ferret_dependencies').all();
|
|
157
162
|
}
|
|
158
163
|
async updateNodeStatus(nodeId, status) {
|
|
159
|
-
this.db.prepare(
|
|
164
|
+
this.db.prepare('UPDATE ferret_nodes SET status = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run(status, nodeId);
|
|
160
165
|
}
|
|
161
166
|
async insertReconciliationLog(log) {
|
|
162
|
-
this.db.prepare(`
|
|
163
|
-
INSERT INTO ferret_reconciliation_log (id, node_id, triggered_by, resolved_by, resolution_notes)
|
|
164
|
-
VALUES (?, ?, ?, ?, ?)
|
|
167
|
+
this.db.prepare(`
|
|
168
|
+
INSERT INTO ferret_reconciliation_log (id, node_id, triggered_by, resolved_by, resolution_notes)
|
|
169
|
+
VALUES (?, ?, ?, ?, ?)
|
|
165
170
|
`).run(log.id, log.node_id, log.triggered_by, log.resolved_by ?? null, log.resolution_notes ?? null);
|
|
166
171
|
}
|
|
167
172
|
async getReconciliationLogs() {
|
|
168
|
-
return this.db.prepare(
|
|
173
|
+
return this.db.prepare('SELECT id, node_id, triggered_by, resolved_by, resolution_notes FROM ferret_reconciliation_log').all();
|
|
169
174
|
}
|
|
170
175
|
async insertPlacementDecision(decision) {
|
|
171
|
-
this.db.prepare(`
|
|
172
|
-
INSERT INTO ferret_placement_decisions (id, node_id, placed_by, reasoning)
|
|
173
|
-
VALUES (?, ?, ?, ?)
|
|
176
|
+
this.db.prepare(`
|
|
177
|
+
INSERT INTO ferret_placement_decisions (id, node_id, placed_by, reasoning)
|
|
178
|
+
VALUES (?, ?, ?, ?)
|
|
174
179
|
`).run(decision.id, decision.node_id, decision.placed_by, decision.reasoning ?? null);
|
|
175
180
|
}
|
|
176
181
|
async getPlacementDecisions() {
|
|
177
|
-
return this.db.prepare(
|
|
182
|
+
return this.db.prepare('SELECT id, node_id, placed_by, reasoning FROM ferret_placement_decisions').all();
|
|
178
183
|
}
|
|
179
184
|
}
|
|
180
185
|
//# sourceMappingURL=sqlite.js.map
|
package/dist/store/sqlite.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/store/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/store/sqlite.ts"],"names":[],"mappings":"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"}
|
package/dist/store/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export type NodeStatus =
|
|
2
|
-
export type ContractStatus =
|
|
1
|
+
export type NodeStatus = 'stable' | 'needs-review' | 'roadmap' | 'blocked';
|
|
2
|
+
export type ContractStatus = 'stable' | 'roadmap' | 'needs-review';
|
|
3
3
|
export interface FerretNode {
|
|
4
4
|
id: string;
|
|
5
5
|
file_path: string;
|
|
@@ -14,6 +14,10 @@ export interface FerretContract {
|
|
|
14
14
|
shape_schema: string;
|
|
15
15
|
type: string;
|
|
16
16
|
status: ContractStatus;
|
|
17
|
+
/** Path to the TypeScript file this contract was generated from (code-first contracts only). */
|
|
18
|
+
code_source_file?: string;
|
|
19
|
+
/** TypeScript symbol name this contract was generated from (code-first contracts only). */
|
|
20
|
+
code_source_symbol?: string;
|
|
17
21
|
}
|
|
18
22
|
export interface FerretDependency {
|
|
19
23
|
id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/store/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,cAAc,GAAG,SAAS,GAAG,SAAS,CAAC;AAC3E,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,SAAS,GAAG,cAAc,CAAC;AAEnE,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/store/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,44 +1,47 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@specferret/core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "SpecFerret core engine — spec drift detection.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./dist/index.js",
|
|
7
|
-
"types": "./dist/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"bun": "./
|
|
11
|
-
"import": "./dist/index.js",
|
|
12
|
-
"types": "./dist/index.d.ts"
|
|
13
|
-
}
|
|
14
|
-
},
|
|
15
|
-
"files": [
|
|
16
|
-
"dist/",
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"ajv
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
},
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@specferret/core",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "SpecFerret core engine — spec drift detection.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"bun": "./src/index.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/",
|
|
17
|
+
"src/",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "bun ../../scripts/clean-dist.ts dist && tsc --project tsconfig.build.json",
|
|
23
|
+
"test": "bun test"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"ajv": "^8.12.0",
|
|
27
|
+
"ajv-formats": "^2.1.1",
|
|
28
|
+
"glob": "^13.0.6",
|
|
29
|
+
"gray-matter": "^4.0.3",
|
|
30
|
+
"tree-sitter": "^0.22.4",
|
|
31
|
+
"tree-sitter-typescript": "^0.23.2",
|
|
32
|
+
"zod": "^3.22.4"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/bun": "^1.3.11",
|
|
36
|
+
"typescript": "^6.0.2"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"bun": ">=1.0.0"
|
|
40
|
+
},
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "git+https://github.com/BenGardiner123/spec-ferret.git"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://specferret.dev"
|
|
47
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { findProjectRoot } from "./utils/paths.js";
|
|
4
|
+
|
|
5
|
+
export interface FerretConfig {
|
|
6
|
+
specDir: string;
|
|
7
|
+
filePattern: string;
|
|
8
|
+
includes?: string[];
|
|
9
|
+
store: "sqlite" | "postgres";
|
|
10
|
+
importSuggestions?: {
|
|
11
|
+
enabled?: boolean;
|
|
12
|
+
};
|
|
13
|
+
codeContracts?: {
|
|
14
|
+
include: string[];
|
|
15
|
+
watchNodes?: string[];
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const DEFAULT_CONFIG: FerretConfig = {
|
|
20
|
+
specDir: "contracts/",
|
|
21
|
+
filePattern: "**/*.contract.md",
|
|
22
|
+
includes: ["**/*.contract.md"],
|
|
23
|
+
store: "sqlite",
|
|
24
|
+
importSuggestions: {
|
|
25
|
+
enabled: true,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Loads ferret.config.json from the project root.
|
|
31
|
+
* Falls back to DEFAULT_CONFIG if the file is not found.
|
|
32
|
+
*/
|
|
33
|
+
export function loadConfig(): FerretConfig {
|
|
34
|
+
const root = findProjectRoot();
|
|
35
|
+
const configPath = path.join(root, "ferret.config.json");
|
|
36
|
+
|
|
37
|
+
if (!fs.existsSync(configPath)) {
|
|
38
|
+
return { ...DEFAULT_CONFIG };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const raw = fs.readFileSync(configPath, "utf-8");
|
|
43
|
+
const parsed = JSON.parse(raw) as Partial<FerretConfig>;
|
|
44
|
+
return { ...DEFAULT_CONFIG, ...parsed };
|
|
45
|
+
} catch {
|
|
46
|
+
return { ...DEFAULT_CONFIG };
|
|
47
|
+
}
|
|
48
|
+
}
|