@mrsf/cli 0.4.3 → 0.5.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 +29 -0
- package/dist/browser.cjs +887 -0
- package/dist/browser.cjs.map +7 -0
- package/dist/browser.d.ts +11 -1
- package/dist/browser.js +9 -0
- package/dist/index.cjs +2137 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.ts +11 -1
- package/dist/index.js +10 -0
- package/dist/lib/comments.js +2 -2
- package/dist/lib/fuzzy.js +15 -152
- package/dist/lib/identity.d.ts +12 -0
- package/dist/lib/identity.js +23 -0
- package/dist/lib/reanchor-core.d.ts +4 -1
- package/dist/lib/reanchor-core.js +62 -0
- package/dist/lib/reanchor.d.ts +1 -1
- package/dist/lib/reanchor.js +1 -1
- package/dist/lib/schema.d.ts +106 -0
- package/dist/lib/schema.js +3 -0
- package/dist/lib/types.d.ts +18 -0
- package/dist/lib/validate-core.d.ts +6 -0
- package/dist/lib/validate-core.js +128 -0
- package/dist/lib/validator.js +4 -112
- package/package.json +14 -6
package/dist/lib/validator.js
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MRSF Validator — JSON Schema + cross-field validation per §10.
|
|
3
3
|
*/
|
|
4
|
-
import AjvModule from "ajv";
|
|
5
|
-
import addFormatsModule from "ajv-formats";
|
|
6
|
-
// ESM interop: handle both default and namespace imports
|
|
7
|
-
const Ajv = AjvModule.default ?? AjvModule;
|
|
8
|
-
const addFormats = addFormatsModule.default ?? addFormatsModule;
|
|
9
4
|
import { readFile } from "node:fs/promises";
|
|
10
5
|
import path from "node:path";
|
|
11
6
|
import { fileURLToPath } from "node:url";
|
|
12
7
|
import { computeHash } from "./writer.js";
|
|
8
|
+
import { validateCrossFields, validateSchema } from "./validate-core.js";
|
|
13
9
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
10
|
let _schemaCache = null;
|
|
15
11
|
async function loadSchema() {
|
|
@@ -44,114 +40,9 @@ export async function validate(doc, options = {}) {
|
|
|
44
40
|
const warnings = [];
|
|
45
41
|
// ── JSON Schema validation ──
|
|
46
42
|
const rawSchema = await loadSchema();
|
|
47
|
-
|
|
48
|
-
const { $schema, ...schema } = rawSchema;
|
|
49
|
-
const ajv = new Ajv({ allErrors: true, strict: false });
|
|
50
|
-
addFormats(ajv);
|
|
51
|
-
const ajvValidate = ajv.compile(schema);
|
|
52
|
-
const schemaValid = ajvValidate(doc);
|
|
53
|
-
if (!schemaValid && ajvValidate.errors) {
|
|
54
|
-
for (const err of ajvValidate.errors) {
|
|
55
|
-
errors.push({
|
|
56
|
-
severity: "error",
|
|
57
|
-
message: `${err.instancePath || "/"}: ${err.message ?? "schema error"}`,
|
|
58
|
-
path: err.instancePath || "/",
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
}
|
|
43
|
+
validateSchema(doc, rawSchema, errors);
|
|
62
44
|
// ── Cross-field validation (§10) ──
|
|
63
|
-
|
|
64
|
-
const ids = new Set();
|
|
65
|
-
for (let i = 0; i < doc.comments.length; i++) {
|
|
66
|
-
const c = doc.comments[i];
|
|
67
|
-
const prefix = `/comments/${i}`;
|
|
68
|
-
// Unique id check
|
|
69
|
-
if (c.id) {
|
|
70
|
-
if (ids.has(c.id)) {
|
|
71
|
-
errors.push({
|
|
72
|
-
severity: "error",
|
|
73
|
-
message: `Duplicate comment id "${c.id}"`,
|
|
74
|
-
path: `${prefix}/id`,
|
|
75
|
-
commentId: c.id,
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
ids.add(c.id);
|
|
79
|
-
}
|
|
80
|
-
// end_line ≥ line
|
|
81
|
-
if (c.line != null && c.end_line != null && c.end_line < c.line) {
|
|
82
|
-
errors.push({
|
|
83
|
-
severity: "error",
|
|
84
|
-
message: `end_line (${c.end_line}) must be ≥ line (${c.line})`,
|
|
85
|
-
path: `${prefix}/end_line`,
|
|
86
|
-
commentId: c.id,
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
// end_column ≥ start_column when same line
|
|
90
|
-
if (c.start_column != null &&
|
|
91
|
-
c.end_column != null &&
|
|
92
|
-
(c.line == null || c.end_line == null || c.line === c.end_line) &&
|
|
93
|
-
c.end_column < c.start_column) {
|
|
94
|
-
errors.push({
|
|
95
|
-
severity: "error",
|
|
96
|
-
message: `end_column (${c.end_column}) must be ≥ start_column (${c.start_column}) on the same line`,
|
|
97
|
-
path: `${prefix}/end_column`,
|
|
98
|
-
commentId: c.id,
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
// selected_text length
|
|
102
|
-
if (c.selected_text && c.selected_text.length > 4096) {
|
|
103
|
-
errors.push({
|
|
104
|
-
severity: "error",
|
|
105
|
-
message: `selected_text exceeds 4096 characters (${c.selected_text.length})`,
|
|
106
|
-
path: `${prefix}/selected_text`,
|
|
107
|
-
commentId: c.id,
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
// text length
|
|
111
|
-
if (c.text && c.text.length > 16384) {
|
|
112
|
-
warnings.push({
|
|
113
|
-
severity: "warning",
|
|
114
|
-
message: `text exceeds recommended 16384 characters (${c.text.length})`,
|
|
115
|
-
path: `${prefix}/text`,
|
|
116
|
-
commentId: c.id,
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
// selected_text_hash consistency
|
|
120
|
-
if (c.selected_text && c.selected_text_hash) {
|
|
121
|
-
const expected = computeHash(c.selected_text);
|
|
122
|
-
if (c.selected_text_hash !== expected) {
|
|
123
|
-
warnings.push({
|
|
124
|
-
severity: "warning",
|
|
125
|
-
message: `selected_text_hash mismatch (expected ${expected.slice(0, 12)}…, got ${c.selected_text_hash.slice(0, 12)}…)`,
|
|
126
|
-
path: `${prefix}/selected_text_hash`,
|
|
127
|
-
commentId: c.id,
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
// reply_to resolution
|
|
132
|
-
if (c.reply_to && !ids.has(c.reply_to)) {
|
|
133
|
-
// Check forward references too
|
|
134
|
-
const allIds = doc.comments.map((x) => x.id);
|
|
135
|
-
if (!allIds.includes(c.reply_to)) {
|
|
136
|
-
warnings.push({
|
|
137
|
-
severity: "warning",
|
|
138
|
-
message: `reply_to "${c.reply_to}" does not resolve to any comment id in this file`,
|
|
139
|
-
path: `${prefix}/reply_to`,
|
|
140
|
-
commentId: c.id,
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
// Missing selected_text warning
|
|
145
|
-
if (c.line != null && !c.selected_text) {
|
|
146
|
-
warnings.push({
|
|
147
|
-
severity: "warning",
|
|
148
|
-
message: `Comment has line anchors but no selected_text — anchoring will be fragile across edits`,
|
|
149
|
-
path: `${prefix}/selected_text`,
|
|
150
|
-
commentId: c.id,
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
45
|
+
validateCrossFields(doc, errors, warnings, computeHash);
|
|
155
46
|
const valid = errors.length === 0 && (!options.strict || warnings.length === 0);
|
|
156
47
|
return { valid, errors, warnings };
|
|
157
48
|
}
|
|
@@ -170,6 +61,7 @@ export async function validateFile(filePath, options = {}) {
|
|
|
170
61
|
errors: [
|
|
171
62
|
{
|
|
172
63
|
severity: "error",
|
|
64
|
+
code: "parse-error",
|
|
173
65
|
message: `Failed to parse: ${e.message}`,
|
|
174
66
|
},
|
|
175
67
|
],
|
package/package.json
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrsf/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "CLI and library for the Markdown Review Sidecar Format (MRSF)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
10
11
|
"import": "./dist/index.js",
|
|
11
|
-
"
|
|
12
|
+
"require": "./dist/index.cjs"
|
|
12
13
|
},
|
|
13
14
|
"./browser": {
|
|
15
|
+
"types": "./dist/browser.d.ts",
|
|
16
|
+
"browser": "./dist/browser.js",
|
|
14
17
|
"import": "./dist/browser.js",
|
|
15
|
-
"
|
|
18
|
+
"require": "./dist/browser.cjs"
|
|
16
19
|
}
|
|
17
20
|
},
|
|
18
21
|
"bin": {
|
|
@@ -22,7 +25,7 @@
|
|
|
22
25
|
"node": ">=18"
|
|
23
26
|
},
|
|
24
27
|
"scripts": {
|
|
25
|
-
"build": "tsc",
|
|
28
|
+
"build": "tsc && node esbuild.config.mjs",
|
|
26
29
|
"dev": "tsc --watch",
|
|
27
30
|
"test": "vitest run",
|
|
28
31
|
"test:watch": "vitest",
|
|
@@ -57,6 +60,8 @@
|
|
|
57
60
|
"files": [
|
|
58
61
|
"dist/**/*.js",
|
|
59
62
|
"dist/**/*.d.ts",
|
|
63
|
+
"dist/**/*.cjs",
|
|
64
|
+
"dist/**/*.cjs.map",
|
|
60
65
|
"mrsf.schema.json",
|
|
61
66
|
"README.md",
|
|
62
67
|
"LICENSE"
|
|
@@ -78,6 +83,9 @@
|
|
|
78
83
|
"@types/uuid": "^10.0.0",
|
|
79
84
|
"@vitest/coverage-v8": "^4.0.18",
|
|
80
85
|
"typescript": "^5.8.2",
|
|
81
|
-
"vitest": "^4.0.18"
|
|
82
|
-
|
|
86
|
+
"vitest": "^4.0.18",
|
|
87
|
+
"esbuild": "^0.27.3"
|
|
88
|
+
},
|
|
89
|
+
"module": "./dist/index.js",
|
|
90
|
+
"sideEffects": false
|
|
83
91
|
}
|