@vibe-agent-toolkit/resources 0.1.36 → 0.1.38
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 +2 -2
- package/dist/ajv-factory.d.ts +33 -0
- package/dist/ajv-factory.d.ts.map +1 -0
- package/dist/ajv-factory.js +51 -0
- package/dist/ajv-factory.js.map +1 -0
- package/dist/config-parser.d.ts +0 -18
- package/dist/config-parser.d.ts.map +1 -1
- package/dist/config-parser.js +5 -45
- package/dist/config-parser.js.map +1 -1
- package/dist/frontmatter-editor.d.ts +45 -0
- package/dist/frontmatter-editor.d.ts.map +1 -0
- package/dist/frontmatter-editor.js +161 -0
- package/dist/frontmatter-editor.js.map +1 -0
- package/dist/frontmatter-validator.d.ts.map +1 -1
- package/dist/frontmatter-validator.js +11 -6
- package/dist/frontmatter-validator.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/json-pointer-path.d.ts +13 -0
- package/dist/json-pointer-path.d.ts.map +1 -0
- package/dist/json-pointer-path.js +30 -0
- package/dist/json-pointer-path.js.map +1 -0
- package/dist/link-parser.js +2 -2
- package/dist/link-parser.js.map +1 -1
- package/dist/link-validator.d.ts +22 -0
- package/dist/link-validator.d.ts.map +1 -1
- package/dist/link-validator.js +126 -75
- package/dist/link-validator.js.map +1 -1
- package/dist/rewriter-helpers.d.ts +49 -0
- package/dist/rewriter-helpers.d.ts.map +1 -0
- package/dist/rewriter-helpers.js +142 -0
- package/dist/rewriter-helpers.js.map +1 -0
- package/dist/types/resource-parser.js +2 -2
- package/dist/types/resource-parser.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +40 -11
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +39 -13
- package/dist/utils.js.map +1 -1
- package/package.json +5 -5
- package/src/ajv-factory.ts +56 -0
- package/src/config-parser.ts +5 -50
- package/src/frontmatter-editor.ts +214 -0
- package/src/frontmatter-validator.ts +11 -7
- package/src/index.ts +21 -2
- package/src/json-pointer-path.ts +29 -0
- package/src/link-parser.ts +2 -2
- package/src/link-validator.ts +153 -88
- package/src/rewriter-helpers.ts +166 -0
- package/src/types/resource-parser.ts +2 -2
- package/src/types.ts +0 -1
- package/src/utils.ts +57 -14
package/src/utils.ts
CHANGED
|
@@ -73,35 +73,58 @@ export function splitHrefAnchor(href: string): [string, string | undefined] {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
|
-
*
|
|
76
|
+
* Discriminated union returned by {@link resolveLocalHref}.
|
|
77
|
+
*
|
|
78
|
+
* - `anchor_only` — the href was `#fragment` only (no file component).
|
|
79
|
+
* - `resolved` — the href resolved to an absolute filesystem path.
|
|
80
|
+
* - `absolute_no_root` — the href is an RFC 3986 §4.2 absolute-path
|
|
81
|
+
* reference (starts with `/`) but no `projectRoot` was supplied.
|
|
82
|
+
* - `absolute_escapes_root` — the absolute-path reference resolved to a
|
|
83
|
+
* location outside `projectRoot` (e.g., via `..` traversal or a symlink
|
|
84
|
+
* pointing outside the project).
|
|
85
|
+
*/
|
|
86
|
+
export type ResolveLocalHrefResult =
|
|
87
|
+
| { kind: 'anchor_only' }
|
|
88
|
+
| { kind: 'resolved'; resolvedPath: string; anchor: string | undefined }
|
|
89
|
+
| { kind: 'absolute_no_root'; href: string; anchor: string | undefined }
|
|
90
|
+
| { kind: 'absolute_escapes_root'; href: string; anchor: string | undefined };
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Resolve a markdown link href to a filesystem path or a typed failure.
|
|
77
94
|
*
|
|
78
95
|
* Performs the standard href → path conversion used by both audit and validate:
|
|
79
96
|
* 1. Strips anchor fragment (`#section`)
|
|
80
97
|
* 2. Decodes URL-encoded characters (`%20` → space, `%26` → `&`)
|
|
81
|
-
* 3. Resolves the path
|
|
82
|
-
*
|
|
83
|
-
*
|
|
98
|
+
* 3. Resolves the path:
|
|
99
|
+
* - Leading `/` (RFC 3986 §4.2 absolute-path reference) → resolve against
|
|
100
|
+
* `projectRoot`. Requires a `projectRoot`; must not escape it.
|
|
101
|
+
* - Otherwise → resolve relative to the source file's directory.
|
|
84
102
|
*
|
|
85
103
|
* @param href - Raw href from a markdown link
|
|
86
104
|
* @param sourceFilePath - Absolute path of the file containing the link
|
|
87
|
-
* @
|
|
105
|
+
* @param projectRoot - Optional project root for absolute-path references.
|
|
106
|
+
* @returns A {@link ResolveLocalHrefResult} discriminating success vs failure modes.
|
|
88
107
|
*
|
|
89
108
|
* @example
|
|
90
109
|
* ```typescript
|
|
91
110
|
* resolveLocalHref('My%20Folder/doc.md#intro', '/project/README.md')
|
|
92
|
-
* // { resolvedPath: '/project/My Folder/doc.md', anchor: 'intro' }
|
|
111
|
+
* // { kind: 'resolved', resolvedPath: '/project/My Folder/doc.md', anchor: 'intro' }
|
|
93
112
|
*
|
|
94
113
|
* resolveLocalHref('#heading', '/project/README.md')
|
|
95
|
-
* //
|
|
114
|
+
* // { kind: 'anchor_only' }
|
|
115
|
+
*
|
|
116
|
+
* resolveLocalHref('/docs/foo.md', '/project/docs/sub/page.md', '/project')
|
|
117
|
+
* // { kind: 'resolved', resolvedPath: '/project/docs/foo.md', anchor: undefined }
|
|
96
118
|
* ```
|
|
97
119
|
*/
|
|
98
120
|
export function resolveLocalHref(
|
|
99
121
|
href: string,
|
|
100
122
|
sourceFilePath: string,
|
|
101
|
-
|
|
123
|
+
projectRoot?: string,
|
|
124
|
+
): ResolveLocalHrefResult {
|
|
102
125
|
const [fileHref, anchor] = splitHrefAnchor(href);
|
|
103
126
|
if (fileHref === '') {
|
|
104
|
-
return
|
|
127
|
+
return { kind: 'anchor_only' };
|
|
105
128
|
}
|
|
106
129
|
|
|
107
130
|
let decodedHref: string;
|
|
@@ -111,10 +134,22 @@ export function resolveLocalHref(
|
|
|
111
134
|
decodedHref = fileHref;
|
|
112
135
|
}
|
|
113
136
|
|
|
137
|
+
// RFC 3986 §4.2 absolute-path reference — resolve against projectRoot.
|
|
138
|
+
if (decodedHref.startsWith('/')) {
|
|
139
|
+
if (!projectRoot) {
|
|
140
|
+
return { kind: 'absolute_no_root', href: fileHref, anchor };
|
|
141
|
+
}
|
|
142
|
+
const candidate = safePath.resolve(projectRoot, decodedHref.slice(1));
|
|
143
|
+
if (!isWithinProject(candidate, projectRoot)) {
|
|
144
|
+
return { kind: 'absolute_escapes_root', href: fileHref, anchor };
|
|
145
|
+
}
|
|
146
|
+
return { kind: 'resolved', resolvedPath: candidate, anchor };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Relative reference — resolve against the source file's directory.
|
|
114
150
|
const sourceDir = path.dirname(sourceFilePath);
|
|
115
151
|
const resolvedPath = safePath.resolve(sourceDir, decodedHref);
|
|
116
|
-
|
|
117
|
-
return { resolvedPath, anchor };
|
|
152
|
+
return { kind: 'resolved', resolvedPath, anchor };
|
|
118
153
|
}
|
|
119
154
|
|
|
120
155
|
/**
|
|
@@ -135,7 +170,9 @@ export function resolveLocalHref(
|
|
|
135
170
|
* ```
|
|
136
171
|
*/
|
|
137
172
|
export function isWithinProject(filePath: string, projectRoot: string): boolean {
|
|
138
|
-
//
|
|
173
|
+
// Canonicalize both sides symmetrically. Asymmetric handling (realpath one
|
|
174
|
+
// side, resolve the other) false-flags legitimate matches when projectRoot
|
|
175
|
+
// traverses a symlink — e.g. macOS /tmp → /private/tmp, bind mounts.
|
|
139
176
|
let resolvedFilePath: string;
|
|
140
177
|
try {
|
|
141
178
|
// eslint-disable-next-line security/detect-non-literal-fs-filename -- filePath is validated path parameter
|
|
@@ -145,7 +182,13 @@ export function isWithinProject(filePath: string, projectRoot: string): boolean
|
|
|
145
182
|
resolvedFilePath = safePath.resolve(filePath);
|
|
146
183
|
}
|
|
147
184
|
|
|
148
|
-
|
|
185
|
+
let resolvedProjectRoot: string;
|
|
186
|
+
try {
|
|
187
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- projectRoot is validated path parameter
|
|
188
|
+
resolvedProjectRoot = fs.realpathSync(projectRoot);
|
|
189
|
+
} catch {
|
|
190
|
+
resolvedProjectRoot = safePath.resolve(projectRoot);
|
|
191
|
+
}
|
|
149
192
|
|
|
150
193
|
// Normalize to forward slashes for cross-platform comparison
|
|
151
194
|
const normalizedFile = toForwardSlash(resolvedFilePath);
|
|
@@ -199,7 +242,7 @@ export function formatJsonPointerAsDotted(pointer: string): string {
|
|
|
199
242
|
return out;
|
|
200
243
|
}
|
|
201
244
|
|
|
202
|
-
function isCanonicalArrayIndex(s: string): boolean {
|
|
245
|
+
export function isCanonicalArrayIndex(s: string): boolean {
|
|
203
246
|
// Canonical integer per RFC 6901 §4 + JSON canonical form: no leading zeros
|
|
204
247
|
// except for "0" itself.
|
|
205
248
|
if (s === '') return false;
|