@piqit/resolvers 0.0.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/dist/edge.d.ts +15 -0
- package/dist/edge.d.ts.map +1 -0
- package/dist/edge.js +15 -0
- package/dist/edge.js.map +1 -0
- package/dist/file-markdown.d.ts +73 -0
- package/dist/file-markdown.d.ts.map +1 -0
- package/dist/file-markdown.js +201 -0
- package/dist/file-markdown.js.map +1 -0
- package/dist/frontmatter.d.ts +58 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +254 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/markdown.d.ts +95 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +174 -0
- package/dist/markdown.js.map +1 -0
- package/dist/path-pattern.d.ts +96 -0
- package/dist/path-pattern.d.ts.map +1 -0
- package/dist/path-pattern.js +130 -0
- package/dist/path-pattern.js.map +1 -0
- package/dist/static.d.ts +65 -0
- package/dist/static.d.ts.map +1 -0
- package/dist/static.js +194 -0
- package/dist/static.js.map +1 -0
- package/package.json +31 -0
- package/src/edge.ts +15 -0
- package/src/file-markdown.ts +352 -0
- package/src/frontmatter.ts +269 -0
- package/src/index.ts +65 -0
- package/src/markdown.ts +262 -0
- package/src/path-pattern.ts +226 -0
- package/src/static.ts +227 -0
package/dist/edge.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @piqit/resolvers/edge - Edge-compatible resolvers
|
|
3
|
+
*
|
|
4
|
+
* This entry point only exports resolvers that work in edge environments
|
|
5
|
+
* like Cloudflare Workers, where dynamic code generation is not allowed.
|
|
6
|
+
*
|
|
7
|
+
* Use this instead of '@piqit/resolvers' in your Worker:
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* import { staticContent } from "@piqit/resolvers/edge";
|
|
11
|
+
*
|
|
12
|
+
* @packageDocumentation
|
|
13
|
+
*/
|
|
14
|
+
export { staticContent, staticResolver } from "./static";
|
|
15
|
+
//# sourceMappingURL=edge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edge.d.ts","sourceRoot":"","sources":["../src/edge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA"}
|
package/dist/edge.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @piqit/resolvers/edge - Edge-compatible resolvers
|
|
3
|
+
*
|
|
4
|
+
* This entry point only exports resolvers that work in edge environments
|
|
5
|
+
* like Cloudflare Workers, where dynamic code generation is not allowed.
|
|
6
|
+
*
|
|
7
|
+
* Use this instead of '@piqit/resolvers' in your Worker:
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* import { staticContent } from "@piqit/resolvers/edge";
|
|
11
|
+
*
|
|
12
|
+
* @packageDocumentation
|
|
13
|
+
*/
|
|
14
|
+
export { staticContent, staticResolver } from "./static";
|
|
15
|
+
//# sourceMappingURL=edge.js.map
|
package/dist/edge.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edge.js","sourceRoot":"","sources":["../src/edge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem Markdown Resolver
|
|
3
|
+
*
|
|
4
|
+
* A resolver for querying markdown files from the filesystem.
|
|
5
|
+
* Optimized for reading only what's needed based on the query.
|
|
6
|
+
*/
|
|
7
|
+
import type { Resolver, StandardSchema, Infer } from "piqit";
|
|
8
|
+
import { type PathParams } from "./path-pattern";
|
|
9
|
+
import { type BodyOptions, type BodyResult, type Heading } from "./markdown";
|
|
10
|
+
/**
|
|
11
|
+
* Options for creating a file markdown resolver.
|
|
12
|
+
*/
|
|
13
|
+
export interface FileMarkdownOptions<TPath extends string, TFrontmatter extends StandardSchema, TBody extends BodyOptions> {
|
|
14
|
+
/**
|
|
15
|
+
* Base directory for finding files.
|
|
16
|
+
* Can be absolute or relative to cwd.
|
|
17
|
+
*/
|
|
18
|
+
base: string;
|
|
19
|
+
/**
|
|
20
|
+
* Path pattern with {param} placeholders.
|
|
21
|
+
* @example '{year}/{slug}.md'
|
|
22
|
+
*/
|
|
23
|
+
path: TPath;
|
|
24
|
+
/**
|
|
25
|
+
* Schema for validating frontmatter.
|
|
26
|
+
* The schema's inferred type defines filter parameters.
|
|
27
|
+
*/
|
|
28
|
+
frontmatter: TFrontmatter;
|
|
29
|
+
/**
|
|
30
|
+
* Body parsing options.
|
|
31
|
+
* @default { raw: false, html: false, headings: false }
|
|
32
|
+
*/
|
|
33
|
+
body?: TBody;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The shape of results from a file markdown resolver.
|
|
37
|
+
*/
|
|
38
|
+
export interface FileMarkdownResult<TParams, TFrontmatter, TBody extends BodyResult> {
|
|
39
|
+
params: TParams;
|
|
40
|
+
frontmatter: TFrontmatter;
|
|
41
|
+
body: TBody;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Type for body shape based on options.
|
|
45
|
+
*/
|
|
46
|
+
type ComputedBodyShape<T extends BodyOptions | undefined> = T extends BodyOptions ? {
|
|
47
|
+
raw: T["raw"] extends true ? string : never;
|
|
48
|
+
html: T["html"] extends true ? string : never;
|
|
49
|
+
headings: T["headings"] extends true ? Heading[] : never;
|
|
50
|
+
} : Record<string, never>;
|
|
51
|
+
/**
|
|
52
|
+
* Clean up body shape to remove never types.
|
|
53
|
+
*/
|
|
54
|
+
type CleanBodyShape<T> = {
|
|
55
|
+
[K in keyof T as T[K] extends never ? never : K]: T[K];
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Create a filesystem markdown resolver.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const postsResolver = fileMarkdown({
|
|
62
|
+
* base: 'content/posts',
|
|
63
|
+
* path: '{year}/{slug}.md',
|
|
64
|
+
* frontmatter: z.object({
|
|
65
|
+
* title: z.string(),
|
|
66
|
+
* status: z.enum(['draft', 'published']),
|
|
67
|
+
* }),
|
|
68
|
+
* body: { html: true, headings: true }
|
|
69
|
+
* })
|
|
70
|
+
*/
|
|
71
|
+
export declare function fileMarkdown<TPath extends string, TFrontmatter extends StandardSchema, TBody extends BodyOptions = Record<string, never>>(options: FileMarkdownOptions<TPath, TFrontmatter, TBody>): Resolver<StandardSchema<Partial<PathParams<TPath>>>, TFrontmatter, StandardSchema<FileMarkdownResult<PathParams<TPath>, Infer<TFrontmatter>, CleanBodyShape<ComputedBodyShape<TBody>>>>>;
|
|
72
|
+
export {};
|
|
73
|
+
//# sourceMappingURL=file-markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-markdown.d.ts","sourceRoot":"","sources":["../src/file-markdown.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAC5D,OAAO,EAAsC,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAEpF,OAAO,EAAqB,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,OAAO,EAAE,MAAM,YAAY,CAAA;AAO/F;;GAEG;AACH,MAAM,WAAW,mBAAmB,CAClC,KAAK,SAAS,MAAM,EACpB,YAAY,SAAS,cAAc,EACnC,KAAK,SAAS,WAAW;IAEzB;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;IAEZ;;;OAGG;IACH,IAAI,EAAE,KAAK,CAAA;IAEX;;;OAGG;IACH,WAAW,EAAE,YAAY,CAAA;IAEzB;;;OAGG;IACH,IAAI,CAAC,EAAE,KAAK,CAAA;CACb;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB,CACjC,OAAO,EACP,YAAY,EACZ,KAAK,SAAS,UAAU;IAExB,MAAM,EAAE,OAAO,CAAA;IACf,WAAW,EAAE,YAAY,CAAA;IACzB,IAAI,EAAE,KAAK,CAAA;CACZ;AAED;;GAEG;AACH,KAAK,iBAAiB,CAAC,CAAC,SAAS,WAAW,GAAG,SAAS,IAAI,CAAC,SAAS,WAAW,GAC7E;IACE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,IAAI,GAAG,MAAM,GAAG,KAAK,CAAA;IAC3C,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI,GAAG,MAAM,GAAG,KAAK,CAAA;IAC7C,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,SAAS,IAAI,GAAG,OAAO,EAAE,GAAG,KAAK,CAAA;CACzD,GACD,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;AAEzB;;GAEG;AACH,KAAK,cAAc,CAAC,CAAC,IAAI;KACtB,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACvD,CAAA;AAuHD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAC1B,KAAK,SAAS,MAAM,EACpB,YAAY,SAAS,cAAc,EACnC,KAAK,SAAS,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAEjD,OAAO,EAAE,mBAAmB,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,CAAC,GACvD,QAAQ,CACT,cAAc,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAC1C,YAAY,EACZ,cAAc,CACZ,kBAAkB,CAChB,UAAU,CAAC,KAAK,CAAC,EACjB,KAAK,CAAC,YAAY,CAAC,EACnB,cAAc,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CACzC,CACF,CACF,CA2HA"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem Markdown Resolver
|
|
3
|
+
*
|
|
4
|
+
* A resolver for querying markdown files from the filesystem.
|
|
5
|
+
* Optimized for reading only what's needed based on the query.
|
|
6
|
+
*/
|
|
7
|
+
import { compilePattern, createParamsSchema } from "./path-pattern";
|
|
8
|
+
import { parseFrontmatter } from "./frontmatter";
|
|
9
|
+
import { parseMarkdownBody } from "./markdown";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// Result Schema Factory
|
|
13
|
+
// =============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Create a result schema for the resolver.
|
|
16
|
+
* This schema validates the namespaced result shape.
|
|
17
|
+
*/
|
|
18
|
+
function createResultSchema(_paramNames, frontmatterSchema, bodyOptions) {
|
|
19
|
+
return {
|
|
20
|
+
"~standard": {
|
|
21
|
+
version: 1,
|
|
22
|
+
vendor: "piqit/resolvers",
|
|
23
|
+
validate(value) {
|
|
24
|
+
if (value === null || typeof value !== "object") {
|
|
25
|
+
return { issues: [{ message: "Expected object" }] };
|
|
26
|
+
}
|
|
27
|
+
const obj = value;
|
|
28
|
+
// Validate params
|
|
29
|
+
if (obj.params == null || typeof obj.params !== "object") {
|
|
30
|
+
return { issues: [{ message: "Missing params", path: ["params"] }] };
|
|
31
|
+
}
|
|
32
|
+
// Validate frontmatter using the provided schema
|
|
33
|
+
const fmResult = frontmatterSchema["~standard"].validate(obj.frontmatter);
|
|
34
|
+
if (fmResult.issues) {
|
|
35
|
+
return {
|
|
36
|
+
issues: fmResult.issues.map((issue) => ({
|
|
37
|
+
...issue,
|
|
38
|
+
path: ["frontmatter", ...(issue.path || [])],
|
|
39
|
+
})),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// Validate body shape
|
|
43
|
+
if (bodyOptions.raw || bodyOptions.html || bodyOptions.headings) {
|
|
44
|
+
if (obj.body == null || typeof obj.body !== "object") {
|
|
45
|
+
return { issues: [{ message: "Missing body", path: ["body"] }] };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return { value: obj };
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// =============================================================================
|
|
54
|
+
// Helper Functions
|
|
55
|
+
// =============================================================================
|
|
56
|
+
/**
|
|
57
|
+
* Check if any select paths require frontmatter data.
|
|
58
|
+
*/
|
|
59
|
+
function needsFrontmatter(selectPaths) {
|
|
60
|
+
return selectPaths.some((p) => p.startsWith("frontmatter.") || p === "frontmatter.*");
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Check if any select paths require body data.
|
|
64
|
+
*/
|
|
65
|
+
function needsBody(selectPaths) {
|
|
66
|
+
return selectPaths.some((p) => p.startsWith("body.") || p === "body.*");
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Check if any select paths require params.
|
|
70
|
+
*/
|
|
71
|
+
function needsParams(selectPaths) {
|
|
72
|
+
return selectPaths.some((p) => p.startsWith("params.") || p === "params.*");
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get which body parts are needed based on select paths.
|
|
76
|
+
*/
|
|
77
|
+
function getNeededBodyParts(selectPaths) {
|
|
78
|
+
const result = {};
|
|
79
|
+
for (const path of selectPaths) {
|
|
80
|
+
if (path === "body.*") {
|
|
81
|
+
// Need all body parts
|
|
82
|
+
return { raw: true, html: true, headings: true };
|
|
83
|
+
}
|
|
84
|
+
if (path === "body.raw")
|
|
85
|
+
result.raw = true;
|
|
86
|
+
if (path === "body.html")
|
|
87
|
+
result.html = true;
|
|
88
|
+
if (path === "body.headings")
|
|
89
|
+
result.headings = true;
|
|
90
|
+
}
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Check if filter constraints match frontmatter.
|
|
95
|
+
* Simple equality check for now.
|
|
96
|
+
*/
|
|
97
|
+
function matchesFilter(frontmatter, filter) {
|
|
98
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
99
|
+
if (frontmatter[key] !== value) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
// =============================================================================
|
|
106
|
+
// Resolver Factory
|
|
107
|
+
// =============================================================================
|
|
108
|
+
/**
|
|
109
|
+
* Create a filesystem markdown resolver.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* const postsResolver = fileMarkdown({
|
|
113
|
+
* base: 'content/posts',
|
|
114
|
+
* path: '{year}/{slug}.md',
|
|
115
|
+
* frontmatter: z.object({
|
|
116
|
+
* title: z.string(),
|
|
117
|
+
* status: z.enum(['draft', 'published']),
|
|
118
|
+
* }),
|
|
119
|
+
* body: { html: true, headings: true }
|
|
120
|
+
* })
|
|
121
|
+
*/
|
|
122
|
+
export function fileMarkdown(options) {
|
|
123
|
+
const pattern = compilePattern(options.path);
|
|
124
|
+
const basePath = path.isAbsolute(options.base)
|
|
125
|
+
? options.base
|
|
126
|
+
: path.join(process.cwd(), options.base);
|
|
127
|
+
const bodyOptions = options.body || {};
|
|
128
|
+
// Create schemas
|
|
129
|
+
const scanSchema = createParamsSchema(pattern);
|
|
130
|
+
const resultSchema = createResultSchema(pattern.paramNames, options.frontmatter, bodyOptions);
|
|
131
|
+
return {
|
|
132
|
+
schema: {
|
|
133
|
+
scanParams: scanSchema,
|
|
134
|
+
filterParams: options.frontmatter,
|
|
135
|
+
result: resultSchema,
|
|
136
|
+
},
|
|
137
|
+
async resolve(spec) {
|
|
138
|
+
const results = [];
|
|
139
|
+
// 1. Generate glob pattern from scan constraints
|
|
140
|
+
const globPattern = pattern.toGlob(spec.scan);
|
|
141
|
+
// 2. Find matching files using Bun.Glob
|
|
142
|
+
const glob = new Bun.Glob(globPattern);
|
|
143
|
+
const files = [];
|
|
144
|
+
for await (const file of glob.scan({ cwd: basePath, absolute: false })) {
|
|
145
|
+
files.push(file);
|
|
146
|
+
}
|
|
147
|
+
// 3. Determine what we need to read
|
|
148
|
+
const wantParams = needsParams(spec.select);
|
|
149
|
+
const wantFrontmatter = needsFrontmatter(spec.select);
|
|
150
|
+
const wantBody = needsBody(spec.select);
|
|
151
|
+
const hasFilter = spec.filter && Object.keys(spec.filter).length > 0;
|
|
152
|
+
const neededBodyParts = wantBody ? getNeededBodyParts(spec.select) : {};
|
|
153
|
+
// 4. Process each file
|
|
154
|
+
for (const relativePath of files) {
|
|
155
|
+
// Extract params from path
|
|
156
|
+
const params = pattern.match(relativePath);
|
|
157
|
+
if (!params)
|
|
158
|
+
continue;
|
|
159
|
+
const fullPath = path.join(basePath, relativePath);
|
|
160
|
+
// Read file content only if needed
|
|
161
|
+
let content = null;
|
|
162
|
+
let frontmatter = null;
|
|
163
|
+
let body = null;
|
|
164
|
+
// If filtering or selecting frontmatter, we need to read it
|
|
165
|
+
if (hasFilter || wantFrontmatter) {
|
|
166
|
+
content = await Bun.file(fullPath).text();
|
|
167
|
+
frontmatter = parseFrontmatter(content);
|
|
168
|
+
if (!frontmatter) {
|
|
169
|
+
frontmatter = {};
|
|
170
|
+
}
|
|
171
|
+
// Check filter constraints
|
|
172
|
+
if (hasFilter && !matchesFilter(frontmatter, spec.filter)) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// If selecting body, parse it
|
|
177
|
+
if (wantBody) {
|
|
178
|
+
if (!content) {
|
|
179
|
+
content = await Bun.file(fullPath).text();
|
|
180
|
+
}
|
|
181
|
+
// Only parse the body parts that are needed
|
|
182
|
+
body = parseMarkdownBody(content, neededBodyParts);
|
|
183
|
+
}
|
|
184
|
+
// Build result with only requested fields
|
|
185
|
+
const result = {};
|
|
186
|
+
if (wantParams) {
|
|
187
|
+
result.params = params;
|
|
188
|
+
}
|
|
189
|
+
if (wantFrontmatter) {
|
|
190
|
+
result.frontmatter = frontmatter;
|
|
191
|
+
}
|
|
192
|
+
if (wantBody && body) {
|
|
193
|
+
result.body = body;
|
|
194
|
+
}
|
|
195
|
+
results.push(result);
|
|
196
|
+
}
|
|
197
|
+
return results;
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=file-markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-markdown.js","sourceRoot":"","sources":["../src/file-markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML Frontmatter Extraction
|
|
3
|
+
*
|
|
4
|
+
* Optimized frontmatter parsing that reads only what's needed.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Parse YAML frontmatter from content string.
|
|
8
|
+
*
|
|
9
|
+
* Uses a simple YAML parser that handles common cases:
|
|
10
|
+
* - key: value
|
|
11
|
+
* - key: "quoted value"
|
|
12
|
+
* - key: 'quoted value'
|
|
13
|
+
* - key: [array, items]
|
|
14
|
+
* - Multi-line values with proper indentation
|
|
15
|
+
*
|
|
16
|
+
* @param content - The file content (or just the frontmatter portion)
|
|
17
|
+
* @returns The parsed frontmatter object, or null if not found
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseFrontmatter(content: string): Record<string, unknown> | null;
|
|
20
|
+
/**
|
|
21
|
+
* Extract just the frontmatter portion from content.
|
|
22
|
+
* Returns the raw YAML string without the --- delimiters.
|
|
23
|
+
*
|
|
24
|
+
* @param content - The file content
|
|
25
|
+
* @returns The YAML content, or null if no frontmatter
|
|
26
|
+
*/
|
|
27
|
+
export declare function extractFrontmatterString(content: string): string | null;
|
|
28
|
+
/**
|
|
29
|
+
* Get the byte offset where frontmatter ends (after closing ---).
|
|
30
|
+
* Returns 0 if no frontmatter found.
|
|
31
|
+
*
|
|
32
|
+
* @param content - The file content
|
|
33
|
+
* @returns Byte offset after frontmatter, or 0
|
|
34
|
+
*/
|
|
35
|
+
export declare function getFrontmatterEndOffset(content: string): number;
|
|
36
|
+
/**
|
|
37
|
+
* Read only the frontmatter from a file, optimized for large files.
|
|
38
|
+
*
|
|
39
|
+
* Reads incrementally until we find the closing ---, avoiding reading
|
|
40
|
+
* the entire file into memory.
|
|
41
|
+
*
|
|
42
|
+
* @param path - Path to the markdown file
|
|
43
|
+
* @param maxBytes - Maximum bytes to read looking for frontmatter (default 8KB)
|
|
44
|
+
* @returns The parsed frontmatter, or null if not found
|
|
45
|
+
*/
|
|
46
|
+
export declare function readFrontmatter(path: string, maxBytes?: number): Promise<Record<string, unknown> | null>;
|
|
47
|
+
/**
|
|
48
|
+
* Read frontmatter and return the offset where body starts.
|
|
49
|
+
* Useful when you need both frontmatter and body.
|
|
50
|
+
*
|
|
51
|
+
* @param path - Path to the markdown file
|
|
52
|
+
* @returns Object with frontmatter and body start offset
|
|
53
|
+
*/
|
|
54
|
+
export declare function readFrontmatterWithOffset(path: string): Promise<{
|
|
55
|
+
frontmatter: Record<string, unknown> | null;
|
|
56
|
+
bodyOffset: number;
|
|
57
|
+
}>;
|
|
58
|
+
//# sourceMappingURL=frontmatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../src/frontmatter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAMhF;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGvE;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAI/D;AA+JD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,QAAQ,SAAO,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAazC;AAED;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAY9E"}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML Frontmatter Extraction
|
|
3
|
+
*
|
|
4
|
+
* Optimized frontmatter parsing that reads only what's needed.
|
|
5
|
+
*/
|
|
6
|
+
// =============================================================================
|
|
7
|
+
// Frontmatter Parsing
|
|
8
|
+
// =============================================================================
|
|
9
|
+
/**
|
|
10
|
+
* Regex to match YAML frontmatter block at the start of content.
|
|
11
|
+
* Matches --- at start, captures content, ends with ---
|
|
12
|
+
*/
|
|
13
|
+
const FRONTMATTER_REGEX = /^---\r?\n([\s\S]*?)\r?\n---/;
|
|
14
|
+
/**
|
|
15
|
+
* Parse YAML frontmatter from content string.
|
|
16
|
+
*
|
|
17
|
+
* Uses a simple YAML parser that handles common cases:
|
|
18
|
+
* - key: value
|
|
19
|
+
* - key: "quoted value"
|
|
20
|
+
* - key: 'quoted value'
|
|
21
|
+
* - key: [array, items]
|
|
22
|
+
* - Multi-line values with proper indentation
|
|
23
|
+
*
|
|
24
|
+
* @param content - The file content (or just the frontmatter portion)
|
|
25
|
+
* @returns The parsed frontmatter object, or null if not found
|
|
26
|
+
*/
|
|
27
|
+
export function parseFrontmatter(content) {
|
|
28
|
+
const match = FRONTMATTER_REGEX.exec(content);
|
|
29
|
+
if (!match)
|
|
30
|
+
return null;
|
|
31
|
+
const yaml = match[1];
|
|
32
|
+
return parseSimpleYaml(yaml);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Extract just the frontmatter portion from content.
|
|
36
|
+
* Returns the raw YAML string without the --- delimiters.
|
|
37
|
+
*
|
|
38
|
+
* @param content - The file content
|
|
39
|
+
* @returns The YAML content, or null if no frontmatter
|
|
40
|
+
*/
|
|
41
|
+
export function extractFrontmatterString(content) {
|
|
42
|
+
const match = FRONTMATTER_REGEX.exec(content);
|
|
43
|
+
return match ? match[1] : null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get the byte offset where frontmatter ends (after closing ---).
|
|
47
|
+
* Returns 0 if no frontmatter found.
|
|
48
|
+
*
|
|
49
|
+
* @param content - The file content
|
|
50
|
+
* @returns Byte offset after frontmatter, or 0
|
|
51
|
+
*/
|
|
52
|
+
export function getFrontmatterEndOffset(content) {
|
|
53
|
+
const match = FRONTMATTER_REGEX.exec(content);
|
|
54
|
+
if (!match)
|
|
55
|
+
return 0;
|
|
56
|
+
return match[0].length;
|
|
57
|
+
}
|
|
58
|
+
// =============================================================================
|
|
59
|
+
// Simple YAML Parser
|
|
60
|
+
// =============================================================================
|
|
61
|
+
/**
|
|
62
|
+
* Parse simple YAML into an object.
|
|
63
|
+
* Handles the common patterns found in markdown frontmatter.
|
|
64
|
+
*/
|
|
65
|
+
function parseSimpleYaml(yaml) {
|
|
66
|
+
const result = {};
|
|
67
|
+
const lines = yaml.split(/\r?\n/);
|
|
68
|
+
let currentKey = null;
|
|
69
|
+
let currentValue = [];
|
|
70
|
+
let inMultiline = false;
|
|
71
|
+
let inBlockArray = false;
|
|
72
|
+
let blockArrayItems = [];
|
|
73
|
+
let multilineIndent = 0;
|
|
74
|
+
function commitValue() {
|
|
75
|
+
if (currentKey) {
|
|
76
|
+
if (inBlockArray) {
|
|
77
|
+
// Commit block array
|
|
78
|
+
result[currentKey] = blockArrayItems;
|
|
79
|
+
blockArrayItems = [];
|
|
80
|
+
inBlockArray = false;
|
|
81
|
+
}
|
|
82
|
+
else if (currentValue.length === 1) {
|
|
83
|
+
result[currentKey] = parseYamlValue(currentValue[0]);
|
|
84
|
+
}
|
|
85
|
+
else if (currentValue.length > 1) {
|
|
86
|
+
result[currentKey] = currentValue.join("\n");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
currentKey = null;
|
|
90
|
+
currentValue = [];
|
|
91
|
+
inMultiline = false;
|
|
92
|
+
}
|
|
93
|
+
for (const line of lines) {
|
|
94
|
+
// Check for block array item (- value)
|
|
95
|
+
const arrayItemMatch = line.match(/^(\s+)-\s+(.*)$/);
|
|
96
|
+
if (arrayItemMatch && currentKey && (inBlockArray || (inMultiline && currentValue.length === 0))) {
|
|
97
|
+
inBlockArray = true;
|
|
98
|
+
inMultiline = false;
|
|
99
|
+
const itemValue = arrayItemMatch[2].trim();
|
|
100
|
+
blockArrayItems.push(parseYamlValue(itemValue));
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
// Check for key: value pattern
|
|
104
|
+
const keyMatch = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*)\s*:\s*(.*)$/);
|
|
105
|
+
if (keyMatch && !inMultiline) {
|
|
106
|
+
// Commit previous key-value
|
|
107
|
+
commitValue();
|
|
108
|
+
currentKey = keyMatch[1];
|
|
109
|
+
const valueStr = keyMatch[2].trim();
|
|
110
|
+
if (valueStr === "" || valueStr === "|" || valueStr === ">") {
|
|
111
|
+
// Multiline value or block array starts on next line
|
|
112
|
+
inMultiline = true;
|
|
113
|
+
multilineIndent = 0;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
currentValue = [valueStr];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (inMultiline && currentKey && !inBlockArray) {
|
|
120
|
+
// Continuation of multiline value
|
|
121
|
+
if (line.trim() === "") {
|
|
122
|
+
currentValue.push("");
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
const indent = line.search(/\S/);
|
|
126
|
+
if (indent > 0) {
|
|
127
|
+
if (multilineIndent === 0) {
|
|
128
|
+
multilineIndent = indent;
|
|
129
|
+
}
|
|
130
|
+
currentValue.push(line.slice(multilineIndent));
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
// No indent means new key or end of multiline
|
|
134
|
+
commitValue();
|
|
135
|
+
// Re-process this line
|
|
136
|
+
const reKeyMatch = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*)\s*:\s*(.*)$/);
|
|
137
|
+
if (reKeyMatch) {
|
|
138
|
+
currentKey = reKeyMatch[1];
|
|
139
|
+
const valueStr = reKeyMatch[2].trim();
|
|
140
|
+
if (valueStr === "" || valueStr === "|" || valueStr === ">") {
|
|
141
|
+
inMultiline = true;
|
|
142
|
+
multilineIndent = 0;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
currentValue = [valueStr];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
else if (currentKey && line.trim() === "") {
|
|
152
|
+
// Empty line after value - keep going
|
|
153
|
+
}
|
|
154
|
+
else if (!currentKey && line.trim() !== "") {
|
|
155
|
+
// New key-value
|
|
156
|
+
const newKeyMatch = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*)\s*:\s*(.*)$/);
|
|
157
|
+
if (newKeyMatch) {
|
|
158
|
+
currentKey = newKeyMatch[1];
|
|
159
|
+
const valueStr = newKeyMatch[2].trim();
|
|
160
|
+
if (valueStr === "" || valueStr === "|" || valueStr === ">") {
|
|
161
|
+
inMultiline = true;
|
|
162
|
+
multilineIndent = 0;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
currentValue = [valueStr];
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Commit final value
|
|
171
|
+
commitValue();
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Parse a single YAML value.
|
|
176
|
+
*/
|
|
177
|
+
function parseYamlValue(value) {
|
|
178
|
+
// Remove quotes
|
|
179
|
+
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
180
|
+
return value.slice(1, -1);
|
|
181
|
+
}
|
|
182
|
+
// Check for array
|
|
183
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
184
|
+
const inner = value.slice(1, -1);
|
|
185
|
+
if (inner.trim() === "")
|
|
186
|
+
return [];
|
|
187
|
+
return inner.split(",").map((item) => parseYamlValue(item.trim()));
|
|
188
|
+
}
|
|
189
|
+
// Check for booleans
|
|
190
|
+
if (value === "true")
|
|
191
|
+
return true;
|
|
192
|
+
if (value === "false")
|
|
193
|
+
return false;
|
|
194
|
+
// Check for null
|
|
195
|
+
if (value === "null" || value === "~")
|
|
196
|
+
return null;
|
|
197
|
+
// Check for numbers
|
|
198
|
+
const num = Number(value);
|
|
199
|
+
if (!isNaN(num) && value !== "")
|
|
200
|
+
return num;
|
|
201
|
+
// Check for dates (ISO format)
|
|
202
|
+
if (/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2})?/.test(value)) {
|
|
203
|
+
const date = new Date(value);
|
|
204
|
+
if (!isNaN(date.getTime()))
|
|
205
|
+
return date.toISOString();
|
|
206
|
+
}
|
|
207
|
+
return value;
|
|
208
|
+
}
|
|
209
|
+
// =============================================================================
|
|
210
|
+
// Optimized File Reading
|
|
211
|
+
// =============================================================================
|
|
212
|
+
/**
|
|
213
|
+
* Read only the frontmatter from a file, optimized for large files.
|
|
214
|
+
*
|
|
215
|
+
* Reads incrementally until we find the closing ---, avoiding reading
|
|
216
|
+
* the entire file into memory.
|
|
217
|
+
*
|
|
218
|
+
* @param path - Path to the markdown file
|
|
219
|
+
* @param maxBytes - Maximum bytes to read looking for frontmatter (default 8KB)
|
|
220
|
+
* @returns The parsed frontmatter, or null if not found
|
|
221
|
+
*/
|
|
222
|
+
export async function readFrontmatter(path, maxBytes = 8192) {
|
|
223
|
+
try {
|
|
224
|
+
const file = Bun.file(path);
|
|
225
|
+
const size = file.size;
|
|
226
|
+
// Read up to maxBytes or file size
|
|
227
|
+
const bytesToRead = Math.min(maxBytes, size);
|
|
228
|
+
const buffer = await file.slice(0, bytesToRead).text();
|
|
229
|
+
return parseFrontmatter(buffer);
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Read frontmatter and return the offset where body starts.
|
|
237
|
+
* Useful when you need both frontmatter and body.
|
|
238
|
+
*
|
|
239
|
+
* @param path - Path to the markdown file
|
|
240
|
+
* @returns Object with frontmatter and body start offset
|
|
241
|
+
*/
|
|
242
|
+
export async function readFrontmatterWithOffset(path) {
|
|
243
|
+
try {
|
|
244
|
+
const file = Bun.file(path);
|
|
245
|
+
const content = await file.text();
|
|
246
|
+
const frontmatter = parseFrontmatter(content);
|
|
247
|
+
const bodyOffset = getFrontmatterEndOffset(content);
|
|
248
|
+
return { frontmatter, bodyOffset };
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
return { frontmatter: null, bodyOffset: 0 };
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../src/frontmatter.ts"],"names":[],"mappings":"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"}
|