@jk2908/mdsrc 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/CHANGELOG.md +15 -0
- package/README.md +35 -11
- package/dist/index.d.ts +4 -3
- package/dist/index.js +69 -18
- package/dist/index.js.map +13 -0
- package/dist/types.d.ts +13 -1
- package/package.json +12 -14
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.0 - 2026-05-07
|
|
4
|
+
|
|
5
|
+
- Breaking: replaced the generated `body` field with `html` and `markdown` on every entry.
|
|
6
|
+
- Added markdown rendering through `markdown-it`, with hard line breaks preserved and raw HTML escaped by default.
|
|
7
|
+
- Added root-level `plugins` support for shared markdown-it plugins across every collection.
|
|
8
|
+
- Moved the publishable package into `packages/mdsrc` and updated the examples to consume `@jk2908/mdsrc` like a normal installed package.
|
|
9
|
+
- Fixed generated `.mdsrc` declarations so consumers pick up the `html` and `markdown` fields correctly.
|
|
10
|
+
|
|
11
|
+
## 0.1.4 - 2026-04-27
|
|
12
|
+
|
|
13
|
+
- Fixed generated `.mdsrc/index.d.ts` to export collection symbols directly, so root `.mdsrc` imports like `import { allPosts } from '../../.mdsrc'` typecheck correctly.
|
|
14
|
+
- Fixed `@jk2908/mdsrc` runtime imports in Vite apps by resolving the package name to generated collection data instead of the plugin package entry.
|
|
15
|
+
- Switched generated collection module filenames to lowercase while keeping the exported symbol names unchanged.
|
package/README.md
CHANGED
|
@@ -12,36 +12,60 @@ npm install @jk2908/mdsrc
|
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
14
|
import plugin from '@jk2908/mdsrc'
|
|
15
|
+
import comark from '@comark/markdown-it'
|
|
15
16
|
import { defineConfig } from 'vite'
|
|
16
17
|
|
|
17
18
|
export default defineConfig({
|
|
18
19
|
plugins: [
|
|
19
|
-
plugin(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
plugin({
|
|
21
|
+
plugins: [comark],
|
|
22
|
+
collections: [
|
|
23
|
+
{
|
|
24
|
+
dir: 'content',
|
|
25
|
+
name: 'post',
|
|
26
|
+
schema: {
|
|
27
|
+
title: { type: 'string' },
|
|
28
|
+
},
|
|
25
29
|
},
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
],
|
|
31
|
+
}),
|
|
28
32
|
],
|
|
29
33
|
})
|
|
30
34
|
```
|
|
31
35
|
|
|
32
|
-
The plugin reads markdown content, validates frontmatter against your schema, and generates typed modules during build and watch. Collection config
|
|
36
|
+
The plugin reads markdown content, validates frontmatter against your schema, and generates typed modules during build and watch. Root config uses `collections`, optional `plugins`, and `logger`. Collection config uses `name`, `dir`, and `schema`.
|
|
33
37
|
|
|
34
|
-
|
|
38
|
+
Each entry exports both `html` and `markdown`.
|
|
39
|
+
|
|
40
|
+
- `html` is rendered with `markdown-it`, with hard line breaks preserved.
|
|
41
|
+
- Raw HTML is escaped by default because the renderer runs with `html: false`.
|
|
42
|
+
- `markdown` preserves the original body for custom renderers like `@comark/react`.
|
|
43
|
+
|
|
44
|
+
Root `plugins` accepts markdown-it plugins directly or tuples like `[plugin, ...args]` and applies them to every collection.
|
|
45
|
+
|
|
46
|
+
See `examples/basic` for the default HTML output flow and `examples/components` for the shared `@comark/markdown-it` plugin used with React.
|
|
47
|
+
|
|
48
|
+
If you configure a collection with `name: 'post'`, `mdsrc` exposes `allPosts` from the package root.
|
|
35
49
|
|
|
36
50
|
```ts
|
|
37
|
-
import { allPosts } from '
|
|
51
|
+
import { allPosts } from '@jk2908/mdsrc'
|
|
38
52
|
|
|
39
53
|
export const summaries = allPosts.map(post => ({
|
|
40
54
|
title: post.title,
|
|
41
55
|
slug: post.__mdsrc.slug,
|
|
56
|
+
html: post.html,
|
|
57
|
+
markdown: post.markdown,
|
|
42
58
|
}))
|
|
43
59
|
```
|
|
44
60
|
|
|
61
|
+
If you want the generated collection module directly, you can also import the collection subpath.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { allPosts } from '@jk2908/mdsrc/post'
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The generated files live in `./.mdsrc` on disk, so you can import them directly via paths like `./.mdsrc/index.js`, but `.mdsrc` itself is not a module ID the plugin resolves. The stable import IDs are `@jk2908/mdsrc` and `@jk2908/mdsrc/<collection>`.
|
|
68
|
+
|
|
45
69
|
## License
|
|
46
70
|
|
|
47
71
|
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Plugin } from 'vite';
|
|
2
|
-
import type { BuildContext,
|
|
2
|
+
import type { BuildContext, PluginConfig } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Read every markdown file in a collection and turn it into the raw entry shape
|
|
5
5
|
* add mdsrc metadata like slug and filename alongside the trimmed body
|
|
@@ -10,11 +10,12 @@ export declare function create(dir: string, buildContext: BuildContext): Promise
|
|
|
10
10
|
slug: string;
|
|
11
11
|
filename: string;
|
|
12
12
|
};
|
|
13
|
-
|
|
13
|
+
html: string;
|
|
14
|
+
markdown: string;
|
|
14
15
|
}[]>;
|
|
15
16
|
/**
|
|
16
17
|
* Build the vite plugin that validates collections and writes the generated modules
|
|
17
18
|
* keep the runtime data and declaration files in the same pass
|
|
18
19
|
* resolve package imports from the generated directory
|
|
19
20
|
*/
|
|
20
|
-
export default function
|
|
21
|
+
export default function mdsrc(config: PluginConfig): Plugin;
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { realpathSync } from "node:fs";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import MarkdownIt from "markdown-it";
|
|
5
6
|
|
|
6
7
|
// src/config.ts
|
|
7
8
|
var NAME = "mdsrc";
|
|
@@ -115,12 +116,15 @@ function debounce(fn, wait) {
|
|
|
115
116
|
|
|
116
117
|
// src/index.ts
|
|
117
118
|
var fileCache = new Map;
|
|
119
|
+
function toModuleName(name) {
|
|
120
|
+
return name.toLowerCase();
|
|
121
|
+
}
|
|
118
122
|
function parse(content) {
|
|
119
123
|
const regex = /^---\r?\n([\s\S]*?)\r?\n---([\s\S]*)$/;
|
|
120
124
|
const match = content.match(regex);
|
|
121
125
|
const metadata = {};
|
|
122
126
|
if (!match)
|
|
123
|
-
throw new Error("
|
|
127
|
+
throw new Error("Invalid frontmatter");
|
|
124
128
|
const [, frontmatter, body] = match;
|
|
125
129
|
if (frontmatter) {
|
|
126
130
|
for (const line of frontmatter.split(`
|
|
@@ -132,7 +136,19 @@ function parse(content) {
|
|
|
132
136
|
return { metadata, body };
|
|
133
137
|
}
|
|
134
138
|
async function create(dir, buildContext) {
|
|
135
|
-
const { logger: logger2 } = buildContext;
|
|
139
|
+
const { logger: logger2, plugins = [] } = buildContext;
|
|
140
|
+
const markdown = new MarkdownIt({
|
|
141
|
+
html: false,
|
|
142
|
+
breaks: true
|
|
143
|
+
});
|
|
144
|
+
for (const plugin of plugins) {
|
|
145
|
+
if (typeof plugin === "function") {
|
|
146
|
+
markdown.use(plugin);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const [applyPlugin, ...params] = plugin;
|
|
150
|
+
markdown.use(applyPlugin, ...params);
|
|
151
|
+
}
|
|
136
152
|
try {
|
|
137
153
|
const files = (await fs.readdir(dir)).filter((file) => path.extname(file) === ".md");
|
|
138
154
|
const filePaths = files.map((file) => path.join(dir, file));
|
|
@@ -142,14 +158,16 @@ async function create(dir, buildContext) {
|
|
|
142
158
|
}
|
|
143
159
|
return Promise.all(filePaths.map(async (filePath) => {
|
|
144
160
|
const file = path.basename(filePath);
|
|
145
|
-
const
|
|
161
|
+
const parsed = parse(await fs.readFile(filePath, "utf-8"));
|
|
162
|
+
const body = parsed.body ? parsed.body.trim() : "";
|
|
146
163
|
return {
|
|
147
|
-
...metadata,
|
|
164
|
+
...parsed.metadata,
|
|
148
165
|
__mdsrc: {
|
|
149
166
|
slug: path.basename(file, ".md").toLowerCase().replace(/\s+/g, "-"),
|
|
150
167
|
filename: file
|
|
151
168
|
},
|
|
152
|
-
|
|
169
|
+
html: body ? markdown.render(body).trim() : body,
|
|
170
|
+
markdown: body
|
|
153
171
|
};
|
|
154
172
|
}));
|
|
155
173
|
} catch (err) {
|
|
@@ -279,12 +297,13 @@ async function build(src, buildContext) {
|
|
|
279
297
|
const raw = await create(path.join(process.cwd(), collection.dir), buildContext);
|
|
280
298
|
const validated = await Promise.all(raw.map(async (item) => {
|
|
281
299
|
try {
|
|
282
|
-
const {
|
|
300
|
+
const { html, markdown, __mdsrc, ...metadata } = item;
|
|
283
301
|
const res = validate(metadata, collection.schema);
|
|
284
302
|
if (res.issues)
|
|
285
303
|
throw new Error(JSON.stringify(res.issues, null, 2));
|
|
286
304
|
return {
|
|
287
|
-
|
|
305
|
+
html,
|
|
306
|
+
markdown,
|
|
288
307
|
...res.value,
|
|
289
308
|
__mdsrc
|
|
290
309
|
};
|
|
@@ -303,7 +322,8 @@ async function build(src, buildContext) {
|
|
|
303
322
|
promises.push(maybeWrite(path.join(outDir, "types.ts"), `
|
|
304
323
|
${names.map((name) => `
|
|
305
324
|
export type ${capitalise(name)} = {
|
|
306
|
-
|
|
325
|
+
html: string
|
|
326
|
+
markdown: string
|
|
307
327
|
${Object.entries(collections[name].schema).map(([key, entry]) => `${key}${entry.optional ? "?" : ""}: ${entry.type === "date" ? "string" : entry.type}`).join(`
|
|
308
328
|
`)}
|
|
309
329
|
__mdsrc: {
|
|
@@ -317,6 +337,12 @@ async function build(src, buildContext) {
|
|
|
317
337
|
promises.push(maybeWrite(path.join(outDir, "index.d.ts"), `
|
|
318
338
|
import type { ${names.map((name) => capitalise(name)).join(", ")} } from './types.js'
|
|
319
339
|
|
|
340
|
+
${names.map((name) => `
|
|
341
|
+
export const all${capitalise(pluralise(name, 2))}: ${capitalise(name)}[]
|
|
342
|
+
`).join(`
|
|
343
|
+
|
|
344
|
+
`)}
|
|
345
|
+
|
|
320
346
|
declare module '${PKG_NAME}' {
|
|
321
347
|
${names.map((name) => `
|
|
322
348
|
export const all${capitalise(pluralise(name, 2))}: ${capitalise(name)}[]
|
|
@@ -327,9 +353,10 @@ async function build(src, buildContext) {
|
|
|
327
353
|
`.trim()));
|
|
328
354
|
for (const name of names) {
|
|
329
355
|
const collection = collections[name]?.items;
|
|
330
|
-
|
|
356
|
+
const fileName = toModuleName(name);
|
|
357
|
+
promises.push(maybeWrite(path.join(outDir, `${fileName}.js`), `export const all${capitalise(pluralise(name, 2))} = ${collection?.length ? JSON.stringify(collection) : "[]"}`.trim()));
|
|
331
358
|
}
|
|
332
|
-
promises.push(maybeWrite(path.join(outDir, "index.js"), names.map((name) => `export * from './${name}.js'`).join(`
|
|
359
|
+
promises.push(maybeWrite(path.join(outDir, "index.js"), names.map((name) => `export * from './${toModuleName(name)}.js'`).join(`
|
|
333
360
|
`)));
|
|
334
361
|
const writes = await Promise.all(promises);
|
|
335
362
|
buildContext.names = names;
|
|
@@ -340,8 +367,9 @@ async function build(src, buildContext) {
|
|
|
340
367
|
}
|
|
341
368
|
}
|
|
342
369
|
var normaliseWatchPath = (p) => p.replace(/\\/g, "/");
|
|
343
|
-
function
|
|
344
|
-
const
|
|
370
|
+
function mdsrc(config) {
|
|
371
|
+
const src = config.collections;
|
|
372
|
+
const logger2 = new Logger(config.logger?.level ?? "debug");
|
|
345
373
|
const outDir = path.join(process.cwd(), GENERATED_DIR);
|
|
346
374
|
const watchRoot = normaliseWatchPath(realpathSync.native(process.cwd()));
|
|
347
375
|
const watchedRoots = src.map((c) => `${normaliseWatchPath(path.join(watchRoot, c.dir))}/`);
|
|
@@ -358,6 +386,7 @@ function plugin(src) {
|
|
|
358
386
|
const isWatchedFile = (filePath) => watchedRoots.some((root) => resolveWatchFile(filePath).startsWith(root));
|
|
359
387
|
const buildContext = {
|
|
360
388
|
logger: logger2,
|
|
389
|
+
plugins: config.plugins,
|
|
361
390
|
outDir,
|
|
362
391
|
names: []
|
|
363
392
|
};
|
|
@@ -377,9 +406,9 @@ function plugin(src) {
|
|
|
377
406
|
try {
|
|
378
407
|
const changed = await build(src, buildContext);
|
|
379
408
|
if (changed)
|
|
380
|
-
logger2.info(`[watch]:
|
|
409
|
+
logger2.info(`[watch]: content rebuilt (${rebuildReason})`);
|
|
381
410
|
} catch (err) {
|
|
382
|
-
logger2.error("[watch]
|
|
411
|
+
logger2.error("[watch] content rebuild failed", err);
|
|
383
412
|
}
|
|
384
413
|
} while (rebuildQueued);
|
|
385
414
|
rebuildRunning = false;
|
|
@@ -394,6 +423,27 @@ function plugin(src) {
|
|
|
394
423
|
return {
|
|
395
424
|
name: "mdsrc",
|
|
396
425
|
enforce: "pre",
|
|
426
|
+
config(viteConfig) {
|
|
427
|
+
viteConfig.optimizeDeps ??= {};
|
|
428
|
+
viteConfig.optimizeDeps.exclude = [
|
|
429
|
+
...new Set([...viteConfig.optimizeDeps.exclude ?? [], PKG_NAME])
|
|
430
|
+
];
|
|
431
|
+
viteConfig.resolve ??= {};
|
|
432
|
+
if (Array.isArray(viteConfig.resolve.alias)) {
|
|
433
|
+
viteConfig.resolve.alias = [
|
|
434
|
+
...viteConfig.resolve.alias,
|
|
435
|
+
{
|
|
436
|
+
find: PKG_NAME,
|
|
437
|
+
replacement: path.join(outDir, "index.js")
|
|
438
|
+
}
|
|
439
|
+
];
|
|
440
|
+
} else {
|
|
441
|
+
viteConfig.resolve.alias = {
|
|
442
|
+
...viteConfig.resolve.alias,
|
|
443
|
+
[PKG_NAME]: path.join(outDir, "index.js")
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
},
|
|
397
447
|
async buildStart() {
|
|
398
448
|
await build(src, buildContext);
|
|
399
449
|
},
|
|
@@ -407,8 +457,9 @@ function plugin(src) {
|
|
|
407
457
|
}
|
|
408
458
|
if (id.startsWith(`${PKG_NAME}/`)) {
|
|
409
459
|
const subpath = id.slice(PKG_NAME.length + 1);
|
|
410
|
-
|
|
411
|
-
|
|
460
|
+
const match = buildContext.names.find((name) => name === subpath || toModuleName(name) === subpath);
|
|
461
|
+
if (match) {
|
|
462
|
+
return path.join(outDir, `${toModuleName(match)}.js`);
|
|
412
463
|
}
|
|
413
464
|
}
|
|
414
465
|
return null;
|
|
@@ -416,8 +467,8 @@ function plugin(src) {
|
|
|
416
467
|
};
|
|
417
468
|
}
|
|
418
469
|
export {
|
|
419
|
-
|
|
470
|
+
mdsrc as default,
|
|
420
471
|
create
|
|
421
472
|
};
|
|
422
473
|
|
|
423
|
-
//# debugId=
|
|
474
|
+
//# debugId=4A1919CF4AE2D2C864756E2164756E21
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts", "../src/config.ts", "../src/logger.ts", "../src/utils.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { realpathSync } from 'node:fs'\nimport fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport type { Plugin, ViteDevServer } from 'vite'\n\nimport MarkdownIt from 'markdown-it'\n\nimport type {\n\tBuildContext,\n\tCollection,\n\tEntries,\n\tIssue,\n\tPluginConfig,\n\tRaw,\n\tResult,\n\tSchema,\n} from './types.js'\nimport { GENERATED_DIR, PKG_NAME } from './config.js'\nimport { Logger } from './logger.js'\nimport { capitalise, debounce, pluralise } from './utils.js'\n\nconst fileCache = new Map<string, string>()\n\nfunction toModuleName(name: string) {\n\treturn name.toLowerCase()\n}\n\n/**\n * Split a markdown file into frontmatter data and the body content\n * keep the format small so the parser stays easy to trust\n * fail fast if the opening fence is missing\n */\nfunction parse(content: string) {\n\t// look for one fenced frontmatter block right at the top\n\t// leave the rest of the markdown body alone\n\tconst regex = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---([\\s\\S]*)$/\n\tconst match = content.match(regex)\n\tconst metadata: Entries = {}\n\n\tif (!match) throw new Error('Invalid frontmatter')\n\n\tconst [, frontmatter, body] = match\n\n\tif (frontmatter) {\n\t\t// treat each line as a simple key: value pair\n\t\t// this is a small subset, not full yaml\n\t\tfor (const line of frontmatter.split('\\n')) {\n\t\t\tconst [key, value] = line.split(': ').map(str => str.trim())\n\t\t\tmetadata[key as keyof Entries] = value\n\t\t}\n\t}\n\n\treturn { metadata, body }\n}\n\n/**\n * Read every markdown file in a collection and turn it into the raw entry shape\n * add mdsrc metadata like slug and filename alongside the trimmed body\n * return an empty list if the directory read fails\n */\nexport async function create(dir: string, buildContext: BuildContext) {\n\tconst { logger, plugins = [] } = buildContext\n\n\tconst markdown = new MarkdownIt({\n\t\thtml: false,\n\t\tbreaks: true,\n\t})\n\n\tfor (const plugin of plugins) {\n\t\tif (typeof plugin === 'function') {\n\t\t\tmarkdown.use(plugin)\n\t\t\tcontinue\n\t\t}\n\n\t\tconst [applyPlugin, ...params] = plugin\n\t\tmarkdown.use(applyPlugin, ...params)\n\t}\n\n\ttry {\n\t\t// only pick up markdown files from this directory\n\t\t// leave everything else alone\n\t\tconst files = (await fs.readdir(dir)).filter(\n\t\t\t(file: string) => path.extname(file) === '.md',\n\t\t)\n\t\tconst filePaths = files.map(file => path.join(dir, file))\n\n\t\tif (!files.length) {\n\t\t\tconsole.warn(`mdsrc: ${dir} is empty`)\n\t\t\treturn []\n\t\t}\n\n\t\treturn Promise.all(\n\t\t\tfilePaths.map(async filePath => {\n\t\t\t\tconst file = path.basename(filePath)\n\n\t\t\t\t// keep the parsed fields, body, and mdsrc metadata together\n\t\t\t\t// build the slug from the filename\n\t\t\t\tconst parsed = parse(await fs.readFile(filePath, 'utf-8'))\n\n\t\t\t\tconst body = parsed.body ? parsed.body.trim() : ''\n\n\t\t\t\treturn {\n\t\t\t\t\t...parsed.metadata,\n\t\t\t\t\t__mdsrc: {\n\t\t\t\t\t\tslug: path.basename(file, '.md').toLowerCase().replace(/\\s+/g, '-'),\n\t\t\t\t\t\tfilename: file,\n\t\t\t\t\t},\n\t\t\t\t\thtml: body ? markdown.render(body).trim() : body,\n\t\t\t\t\tmarkdown: body,\n\t\t\t\t} satisfies Raw\n\t\t\t}),\n\t\t)\n\t} catch (err) {\n\t\tlogger.error('[create]: failed to create entries', err)\n\t\treturn []\n\t}\n}\n\n/**\n * Write a file only if the content has changed since the last build\n */\nasync function maybeWrite(filePath: string, content: string) {\n\tconst cached = fileCache.get(filePath)\n\n\tif (cached === content) {\n\t\ttry {\n\t\t\tawait fs.access(filePath)\n\t\t\treturn false\n\t\t} catch (err) {\n\t\t\tif (!(err instanceof Error) || !('code' in err) || err.code !== 'ENOENT') {\n\t\t\t\tthrow err\n\t\t\t}\n\n\t\t\t// file was deleted since the last build, fall through and write it again\n\t\t}\n\t}\n\n\tif (cached === undefined) {\n\t\ttry {\n\t\t\tconst current = await fs.readFile(filePath, 'utf-8')\n\t\t\tfileCache.set(filePath, current)\n\n\t\t\tif (current === content) {\n\t\t\t\tfileCache.set(filePath, content)\n\t\t\t\treturn false\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tif (!(err instanceof Error) || !('code' in err) || err.code !== 'ENOENT') {\n\t\t\t\tthrow err\n\t\t\t}\n\t\t}\n\t}\n\n\t// file is new or changed since the last build, write it and refresh the cache\n\tawait fs.writeFile(filePath, content)\n\tfileCache.set(filePath, content)\n\n\treturn true\n}\n\n/**\n * Check one entry against the declared schema and coerce what can be coerced\n * leave missing optional keys alone instead of treating them as errors\n * normalise dates to iso strings for output\n */\nfunction validate(input: Entries, schema: Schema) {\n\t// keep valid values separate so bad fields never sneak into output\n\tconst validated: Entries = {}\n\t// collect every problem so one pass can report the lot\n\tconst issues: Issue[] = []\n\n\t// bail out early if the frontmatter is not even an object\n\tif (typeof input !== 'object' || input === null) {\n\t\tissues.push({ message: 'Input must be an object' })\n\t\treturn { issues } satisfies Result<Entries>\n\t}\n\n\t// drive validation from the schema so the rules always stay in charge\n\tfor (const key in schema) {\n\t\tconst entry = schema[key]\n\n\t\t// if the key is missing, only complain when the schema says it must exist\n\t\tif (!(key in input)) {\n\t\t\tif (!entry.optional) {\n\t\t\t\tissues.push({ message: `Missing required key: ${key}` })\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// once the key exists, coerce it into the shape the schema expects\n\t\tconst value = input[key]\n\n\t\tswitch (entry.type) {\n\t\t\tcase 'string': {\n\t\t\t\t// strings just need the basic type check and any length limits\n\t\t\t\tif (typeof value !== 'string') {\n\t\t\t\t\tissues.push({ message: `Key ${key} must be a string` })\n\t\t\t\t} else {\n\t\t\t\t\tif (entry.minLength && value.length < entry.minLength) {\n\t\t\t\t\t\tissues.push({\n\t\t\t\t\t\t\tmessage: `Key ${key} must be at least ${entry.minLength} characters`,\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\n\t\t\t\t\tif (entry.maxLength && value.length > entry.maxLength) {\n\t\t\t\t\t\tissues.push({\n\t\t\t\t\t\t\tmessage: `Key ${key} must be at most ${entry.maxLength} characters`,\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\n\t\t\t\t\tvalidated[key] = value\n\t\t\t\t}\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'number': {\n\t\t\t\tlet num = value\n\n\t\t\t\t// frontmatter usually starts life as text, so numeric strings still count\n\t\t\t\tif (typeof value === 'string' && !Number.isNaN(Number(value))) {\n\t\t\t\t\tnum = Number(value)\n\t\t\t\t}\n\n\t\t\t\tif (typeof num !== 'number') {\n\t\t\t\t\tissues.push({ message: `Key ${key} must be a number` })\n\t\t\t\t} else {\n\t\t\t\t\tvalidated[key] = num\n\t\t\t\t}\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'boolean': {\n\t\t\t\tlet bool = value\n\t\t\t\t// booleans often come through as the words true or false\n\t\t\t\tif (typeof value === 'string') {\n\t\t\t\t\tif (value.toLowerCase() === 'true') {\n\t\t\t\t\t\tbool = true\n\t\t\t\t\t} else if (value.toLowerCase() === 'false') {\n\t\t\t\t\t\tbool = false\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (typeof bool !== 'boolean') {\n\t\t\t\t\tissues.push({ message: `Key ${key} must be a boolean` })\n\t\t\t\t} else {\n\t\t\t\t\tvalidated[key] = bool\n\t\t\t\t}\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'date': {\n\t\t\t\t// keep dates as iso strings because that is what generated output exposes\n\t\t\t\tif (typeof value !== 'string') {\n\t\t\t\t\tissues.push({ message: `Key ${key} must be a date` })\n\t\t\t\t} else {\n\t\t\t\t\tconst date = new Date(value)\n\n\t\t\t\t\tif (Number.isNaN(date.getTime())) {\n\t\t\t\t\t\tissues.push({ message: `Key ${key} must be a valid date` })\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvalidated[key] = date.toISOString()\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\t// hand back the clean entry when validation passes\n\t// otherwise return the full issue list\n\treturn (issues.length ? { issues } : { value: validated }) satisfies Result<Entries>\n}\n\nasync function build(src: Collection[], buildContext: BuildContext) {\n\tconst { logger, outDir } = buildContext\n\tlet names: string[] = []\n\n\t// keep each validated collection beside its schema so emit stays in sync\n\tconst collections: Record<\n\t\tstring,\n\t\t{\n\t\t\titems: Raw[]\n\t\t\tschema: Schema\n\t\t}\n\t> = {}\n\n\ttry {\n\t\tif (!outDir) throw new Error('Output directory is not defined')\n\n\t\t// make sure the output directory exists before the writes begin\n\t\t// that way the emit step can stay simple\n\t\tawait fs.mkdir(outDir, { recursive: true })\n\n\t\t// read and validate every collection before writing anything out\n\t\t// this keeps the js and dts outputs in step\n\t\tfor (const collection of src) {\n\t\t\tconst raw = await create(path.join(process.cwd(), collection.dir), buildContext)\n\n\t\t\t// check each raw item before it makes it into the generated collection\n\t\t\t// bad entries get logged and dropped\n\t\t\tconst validated = await Promise.all(\n\t\t\t\traw.map(async item => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst { html, markdown, __mdsrc, ...metadata } = item\n\t\t\t\t\t\tconst res = validate(metadata, collection.schema)\n\n\t\t\t\t\t\tif (res.issues) throw new Error(JSON.stringify(res.issues, null, 2))\n\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\thtml,\n\t\t\t\t\t\t\tmarkdown,\n\t\t\t\t\t\t\t...res.value,\n\t\t\t\t\t\t\t__mdsrc,\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tlogger.error(\n\t\t\t\t\t\t\t`[buildStart]: failed to validate item in ${collection.name}`,\n\t\t\t\t\t\t\terr,\n\t\t\t\t\t\t)\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t)\n\n\t\t\tcollections[collection.name] = {\n\t\t\t\t// keep the cleaned items with the schema they came from\n\t\t\t\t// both js and dts generation read from this shape\n\t\t\t\titems: validated.filter(e => e !== null),\n\t\t\t\tschema: collection.schema,\n\t\t\t}\n\t\t}\n\n\t\t// take the collection names after validation has settled\n\t\t// every generated file then works from the same list\n\t\tnames = Object.keys(collections)\n\t\t// queue the file writes first so the emit phase can run together\n\t\t// wait for them once every output is ready\n\t\tconst promises = []\n\n\t\t// build the type file from the schema rather than the observed data\n\t\t// that keeps optional fields and date output honest\n\t\tpromises.push(\n\t\t\tmaybeWrite(\n\t\t\t\tpath.join(outDir, 'types.ts'),\n\t\t\t\t`\n\t\t\t\t\t${names\n\t\t\t\t\t\t// make one named type per collection so the dts mirrors the js surface.\n\t\t\t\t\t\t// html and markdown are always present on generated entries\n\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\tname => `\n\t\t\t\t\t\t\t\texport type ${capitalise(name)} = {\n\t\t\t\t\t\t\t\t\thtml: string\n\t\t\t\t\t\t\t\t\tmarkdown: string\n\t\t\t\t\t\t\t\t\t${Object.entries(collections[name].schema)\n\t\t\t\t\t\t\t\t\t\t// turn each schema field into a ts property line\n\t\t\t\t\t\t\t\t\t\t// keep optional markers and date strings in step with validation\n\t\t\t\t\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t\t\t\t\t([key, entry]) =>\n\t\t\t\t\t\t\t\t\t\t\t\t`${key}${entry.optional ? '?' : ''}: ${entry.type === 'date' ? 'string' : entry.type}`,\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t.join('\\n ')}\n\t\t\t\t\t\t\t\t\t__mdsrc: {\n\t\t\t\t\t\t\t\t\t\tslug: string\n\t\t\t\t\t\t\t\t\t\tfilename: string\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.join('\\n\\n')}`.trim(),\n\t\t\t),\n\t\t)\n\n\t\t// write the package surface separately so consumers get typed named exports\n\t\t// this mirrors the generated js entry file\n\t\tpromises.push(\n\t\t\tmaybeWrite(\n\t\t\t\tpath.join(outDir, 'index.d.ts'),\n\t\t\t\t`\t\n\t\t\t\t\timport type { ${names.map(name => capitalise(name)).join(', ')} } from './types.js'\n\n\t\t\t\t\t${names\n\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\tname => `\n\t\t\t\t\t\t\t\texport const all${capitalise(pluralise(name, 2))}: ${capitalise(name)}[]\n\t\t\t\t\t\t\t`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.join('\\n\\n')}\n\n\t\t\t\t\tdeclare module '${PKG_NAME}' {\n\t\t\t\t\t\t${names\n\t\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t\tname => `\n\t\t\t\t\t\t\t\t\texport const all${capitalise(pluralise(name, 2))}: ${capitalise(name)}[]\n\t\t\t\t\t\t\t\t`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.join('\\n\\n')}\n\t\t\t\t\t}\n\t\t\t\t`.trim(),\n\t\t\t),\n\t\t)\n\n\t\t// serialise each validated collection as a plain module for vite to load\n\t\t// empty collections still export a stable array shape\n\t\tfor (const name of names) {\n\t\t\tconst collection = collections[name]?.items\n\t\t\tconst fileName = toModuleName(name)\n\n\t\t\tpromises.push(\n\t\t\t\tmaybeWrite(\n\t\t\t\t\tpath.join(outDir, `${fileName}.js`),\n\t\t\t\t\t`export const all${capitalise(pluralise(name, 2))} = ${collection?.length ? JSON.stringify(collection) : '[]'}`.trim(),\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\n\t\t// stitch the per-collection modules into the public js entrypoint\n\t\t// this is the file the root package import resolves to\n\t\tpromises.push(\n\t\t\tmaybeWrite(\n\t\t\t\tpath.join(outDir, 'index.js'),\n\t\t\t\tnames.map(name => `export * from './${toModuleName(name)}.js'`).join('\\n'),\n\t\t\t),\n\t\t)\n\n\t\t// flush every generated artifact once all the content is ready\n\t\t// let any failed write fail the build\n\t\tconst writes = await Promise.all(promises)\n\t\tbuildContext.names = names\n\n\t\treturn writes.some(changed => changed)\n\t} catch (err) {\n\t\tlogger.error('[build]: failed to generate data', err)\n\t\tthrow err\n\t}\n}\n\n// convert watcher paths to a consistent slash format before comparing them\nconst normaliseWatchPath = (p: string) => p.replace(/\\\\/g, '/')\n\n/**\n * Build the vite plugin that validates collections and writes the generated modules\n * keep the runtime data and declaration files in the same pass\n * resolve package imports from the generated directory\n */\nexport default function mdsrc(config: PluginConfig): Plugin {\n\tconst src = config.collections\n\n\t// use one logger for the whole build so every step reports the same way\n\t// stay chatty outside production\n\tconst logger = new Logger(\n\t\tconfig.logger?.level ?? (process.env.NODE_ENV === 'production' ? 'error' : 'debug'),\n\t)\n\n\t// write generated files into a hidden folder at the project root\n\t// keep the generated surface out of src\n\tconst outDir = path.join(process.cwd(), GENERATED_DIR)\n\tconst watchRoot = normaliseWatchPath(realpathSync.native(process.cwd()))\n\tconst watchedRoots = src.map(c => `${normaliseWatchPath(path.join(watchRoot, c.dir))}/`)\n\n\t// watcher events can arrive through symlinked paths like /var while cwd has\n\t// already resolved to /private/var, so canonicalise the parent dir once and\n\t// reattach the file name for stable prefix checks\n\tconst resolveWatchFile = (filePath: string) => {\n\t\tconst absolutePath = path.resolve(watchRoot, filePath)\n\t\tconst parentPath = path.dirname(absolutePath)\n\n\t\ttry {\n\t\t\tconst resolvedParentPath = normaliseWatchPath(realpathSync.native(parentPath))\n\t\t\treturn normaliseWatchPath(\n\t\t\t\tpath.join(resolvedParentPath, path.basename(absolutePath)),\n\t\t\t)\n\t\t} catch {\n\t\t\treturn normaliseWatchPath(absolutePath)\n\t\t}\n\t}\n\n\tconst isWatchedFile = (filePath: string) =>\n\t\twatchedRoots.some(root => resolveWatchFile(filePath).startsWith(root))\n\n\t// pass shared build tools into helpers without dragging lots of state around\n\t// keep the helper signatures small\n\tconst buildContext = {\n\t\tlogger,\n\t\tplugins: config.plugins,\n\t\toutDir,\n\t\tnames: [],\n\t} satisfies BuildContext\n\n\tlet rebuildRunning = false\n\tlet rebuildQueued = false\n\tlet rebuildReason = 'change'\n\tconst rebuild = debounce((event: string, filePath: string) => {\n\t\tconst queue = () => {\n\t\t\tvoid (async () => {\n\t\t\t\t// collapse bursts of file events into one active rebuild plus a single\n\t\t\t\t// queued rerun when changes land mid-build\n\t\t\t\tif (rebuildRunning) {\n\t\t\t\t\trebuildQueued = true\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\trebuildRunning = true\n\n\t\t\t\tdo {\n\t\t\t\t\trebuildQueued = false\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst changed = await build(src, buildContext)\n\n\t\t\t\t\t\tif (changed) logger.info(`[watch]: content rebuilt (${rebuildReason})`)\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tlogger.error('[watch] content rebuild failed', err)\n\t\t\t\t\t}\n\t\t\t\t} while (rebuildQueued)\n\n\t\t\t\trebuildRunning = false\n\t\t\t})()\n\t\t}\n\n\t\t// ignore anything outside the watched content dirs\n\t\tif (!isWatchedFile(filePath)) return\n\n\t\tconst file = resolveWatchFile(filePath)\n\n\t\trebuildReason = `${event}: ${path.relative(watchRoot, file)}`\n\t\tqueue()\n\t}, 75)\n\n\treturn {\n\t\tname: 'mdsrc',\n\t\tenforce: 'pre',\n\t\tconfig(viteConfig) {\n\t\t\tviteConfig.optimizeDeps ??= {}\n\t\t\tviteConfig.optimizeDeps.exclude = [\n\t\t\t\t...new Set([...(viteConfig.optimizeDeps.exclude ?? []), PKG_NAME]),\n\t\t\t]\n\n\t\t\tviteConfig.resolve ??= {}\n\n\t\t\tif (Array.isArray(viteConfig.resolve.alias)) {\n\t\t\t\tviteConfig.resolve.alias = [\n\t\t\t\t\t...viteConfig.resolve.alias,\n\t\t\t\t\t{\n\t\t\t\t\t\tfind: PKG_NAME,\n\t\t\t\t\t\treplacement: path.join(outDir, 'index.js'),\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t} else {\n\t\t\t\tviteConfig.resolve.alias = {\n\t\t\t\t\t...viteConfig.resolve.alias,\n\t\t\t\t\t[PKG_NAME]: path.join(outDir, 'index.js'),\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tasync buildStart() {\n\t\t\tawait build(src, buildContext)\n\t\t},\n\t\tconfigureServer(server: ViteDevServer) {\n\t\t\tlogger.info(\n\t\t\t\t`[configureServer]: Watching for changes in ./${src.map(c => c.dir).join(', ')}...`,\n\t\t\t)\n\n\t\t\tserver.watcher\n\t\t\t\t.on('add', (p: string) => rebuild('add', p))\n\t\t\t\t.on('change', (p: string) => rebuild('change', p))\n\t\t\t\t.on('unlink', (p: string) => rebuild('unlink', p))\n\t\t},\n\t\tresolveId(id) {\n\t\t\t// point imports at generated files rather than source files\n\t\t\t// that makes the package behave like a normal module\n\t\t\tif (id === PKG_NAME) {\n\t\t\t\treturn path.join(outDir, 'index.js')\n\t\t\t}\n\n\t\t\tif (id.startsWith(`${PKG_NAME}/`)) {\n\t\t\t\t// allow collection subpath imports once the build knows their names\n\t\t\t\t// leave unknown subpaths unresolved\n\t\t\t\tconst subpath = id.slice(PKG_NAME.length + 1)\n\t\t\t\tconst match = buildContext.names.find(\n\t\t\t\t\tname => name === subpath || toModuleName(name) === subpath,\n\t\t\t\t)\n\n\t\t\t\tif (match) {\n\t\t\t\t\treturn path.join(outDir, `${toModuleName(match)}.js`)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null\n\t\t},\n\t}\n}\n",
|
|
6
|
+
"export const NAME = 'mdsrc'\nexport const PKG_NAME = `@jk2908/${NAME}`\nexport const GENERATED_DIR = `.${NAME}`",
|
|
7
|
+
"import { NAME } from './config.js'\n\nconst LEVELS = {\n\tdebug: 0,\n\tinfo: 1,\n\twarn: 2,\n\terror: 3,\n\tfatal: 4,\n} as const\n\nexport type LogLevel = keyof typeof LEVELS\n\ntype LogEntry = {\n\tts: number\n\tlevel: LogLevel\n\tmessage: string\n\terror?:\n\t\t| Error\n\t\t| {\n\t\t\t\tmessage: string\n\t\t\t\tstack?: string\n\t\t\t\tcause?: unknown\n\t\t }\n}\n\n/**\n * Log messages with different severity levels\n */\nexport class Logger {\n\tstatic #defaultLevel: LogLevel = 'info'\n\n\t#level?: LogLevel\n\n\tconstructor(level?: LogLevel) {\n\t\tthis.#level = level\n\t}\n\n\tstatic set defaultLevel(level: LogLevel) {\n\t\tLogger.#defaultLevel = level\n\t}\n\n\tstatic get defaultLevel() {\n\t\treturn Logger.#defaultLevel\n\t}\n\n\t/**\n\t * Convert a value to an Error instance\n\t */\n\tstatic toError(err: unknown) {\n\t\treturn err instanceof Error ? err : new Error(String(err), { cause: err })\n\t}\n\n\t/**\n\t * Stringify the error for logging\n\t */\n\tstatic print(err: unknown) {\n\t\tif (err instanceof Error) {\n\t\t\treturn err.message + (err.stack ? `\\n${err.stack}` : '')\n\t\t}\n\n\t\t// for plain objects, attempt to stringify with indentation\n\t\t// for readability\n\t\tif (typeof err === 'object' && err !== null) {\n\t\t\ttry {\n\t\t\t\treturn JSON.stringify(err, null, 2)\n\t\t\t} catch {\n\t\t\t\t// if stringify fails (e.g. circular reference), fall back\n\t\t\t\t// to basic string conversion\n\t\t\t\treturn String(err)\n\t\t\t}\n\t\t}\n\n\t\treturn String(err)\n\t}\n\n\tset level(level: LogLevel) {\n\t\tthis.#level = level\n\t}\n\n\tget level() {\n\t\treturn this.#level ?? Logger.#defaultLevel\n\t}\n\n\t/**\n\t * Log a message with a specific level\n\t */\n\tlog(level: LogLevel, message: string, error?: Error) {\n\t\tif (LEVELS[level] < LEVELS[this.level]) return\n\n\t\tconst entry: LogEntry = {\n\t\t\tts: Date.now(),\n\t\t\tlevel,\n\t\t\tmessage,\n\t\t}\n\n\t\tif (level === 'error' || level === 'fatal') {\n\t\t\tentry.error = error ? Logger.toError(error) : new Error(message)\n\t\t}\n\n\t\tconst line = `[${NAME}] [${entry.ts}] [${level.toUpperCase()}] ${message}`\n\t\tconst extra = entry.error ? `\\n${Logger.print(entry.error)}` : ''\n\n\t\tif (level === 'warn') {\n\t\t\tconsole.warn(line, extra)\n\t\t\treturn\n\t\t}\n\n\t\tif (level === 'error' || level === 'fatal') {\n\t\t\tconsole.error(line, extra)\n\t\t\treturn\n\t\t}\n\n\t\tconsole.log(line, extra)\n\t}\n\n\t/**\n\t * Log a debug message\n\t */\n\tdebug(...messages: string[]) {\n\t\tthis.log('debug', messages.join(' '))\n\t}\n\n\t/**\n\t * Log an info message\n\t */\n\tinfo(...messages: string[]) {\n\t\tthis.log('info', messages.join(' '))\n\t}\n\n\t/**\n\t * Log a warning message\n\t */\n\twarn(...messages: string[]) {\n\t\tthis.log('warn', messages.join(' '))\n\t}\n\n\t/**\n\t * Log an error message\n\t */\n\terror(message: string, error?: unknown) {\n\t\tthis.log('error', message, error === undefined ? undefined : Logger.toError(error))\n\t}\n\n\t/**\n\t * Log a fatal error message\n\t */\n\tfatal(message: string, error?: unknown) {\n\t\tthis.log('fatal', message, error === undefined ? undefined : Logger.toError(error))\n\t}\n}\n\nexport const logger = new Logger(\n\tprocess.env.NODE_ENV === 'production' ? 'error' : 'debug',\n)\n",
|
|
8
|
+
"export function capitalise(str: string) {\n\treturn str.charAt(0).toUpperCase() + str.slice(1)\n}\n\nexport function pluralise(str: string, count: number) {\n\treturn count === 1 ? str : str.endsWith('s') ? str : `${str}s`\n}\n\nexport function debounce<T extends unknown[]>(fn: (...args: T) => void, wait: number) {\n\tlet timeoutId: ReturnType<typeof setTimeout> | null = null\n\n\treturn (...args: T) => {\n\t\tif (timeoutId) {\n\t\t\tclearTimeout(timeoutId)\n\t\t}\n\n\t\ttimeoutId = setTimeout(() => {\n\t\t\tfn.apply(null, args)\n\t\t}, wait)\n\t}\n}\n"
|
|
9
|
+
],
|
|
10
|
+
"mappings": "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",
|
|
11
|
+
"debugId": "4A1919CF4AE2D2C864756E2164756E21",
|
|
12
|
+
"names": []
|
|
13
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
|
+
import type MarkdownIt from 'markdown-it';
|
|
1
2
|
import type { LogLevel, Logger } from './logger.js';
|
|
3
|
+
type MarkdownItUseArgs = Parameters<MarkdownIt['use']>;
|
|
4
|
+
export type MarkdownPlugin = MarkdownItUseArgs[0];
|
|
5
|
+
export type MarkdownPluginUse = MarkdownPlugin | readonly [
|
|
6
|
+
plugin: MarkdownPlugin,
|
|
7
|
+
...params: MarkdownItUseArgs extends [unknown, ...infer Params] ? Params : never
|
|
8
|
+
];
|
|
2
9
|
export type PluginConfig = {
|
|
10
|
+
collections: Collection[];
|
|
3
11
|
logger?: {
|
|
4
12
|
level?: LogLevel;
|
|
5
13
|
};
|
|
14
|
+
plugins?: MarkdownPluginUse[];
|
|
6
15
|
};
|
|
7
16
|
export type BuildContext = {
|
|
8
17
|
logger: InstanceType<typeof Logger>;
|
|
18
|
+
plugins?: MarkdownPluginUse[];
|
|
9
19
|
outDir?: string;
|
|
10
20
|
names?: string[];
|
|
11
21
|
};
|
|
@@ -27,7 +37,8 @@ export type Raw = {
|
|
|
27
37
|
slug: string;
|
|
28
38
|
filename: string;
|
|
29
39
|
};
|
|
30
|
-
|
|
40
|
+
html: string;
|
|
41
|
+
markdown: string;
|
|
31
42
|
} & Entries;
|
|
32
43
|
export type Types = Record<string, string>;
|
|
33
44
|
export type Issue = {
|
|
@@ -42,3 +53,4 @@ export type Success<Output> = {
|
|
|
42
53
|
readonly types?: Record<string, string>;
|
|
43
54
|
};
|
|
44
55
|
export type Result<Output> = Success<Output> | Fail;
|
|
56
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jk2908/mdsrc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Jerome Kenway",
|
|
6
|
+
"description": "A Vite plugin for turning structured Markdown content into importable, type-safe modules",
|
|
6
7
|
"repository": {
|
|
7
8
|
"type": "git",
|
|
8
9
|
"url": "git+https://github.com/jk2908/mdsrc.git"
|
|
@@ -11,18 +12,14 @@
|
|
|
11
12
|
"types": "./dist/index.d.ts",
|
|
12
13
|
"scripts": {
|
|
13
14
|
"build": "bun run ./build.ts && bun x tsc --project tsconfig.json --emitDeclarationOnly",
|
|
14
|
-
"test": "bun test"
|
|
15
|
+
"test": "cd ../.. && bun test"
|
|
15
16
|
},
|
|
16
|
-
"
|
|
17
|
-
"@types/
|
|
18
|
-
"
|
|
19
|
-
"@types/node": "^24.0.1",
|
|
20
|
-
"oxfmt": "^0.35.0",
|
|
21
|
-
"oxlint": "^1.50.0",
|
|
22
|
-
"vite": "^5.4.2"
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@types/markdown-it": "^14.1.2",
|
|
19
|
+
"markdown-it": "^14.1.0"
|
|
23
20
|
},
|
|
24
21
|
"peerDependencies": {
|
|
25
|
-
"vite": "^4.0.0"
|
|
22
|
+
"vite": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
|
|
26
23
|
},
|
|
27
24
|
"publishConfig": {
|
|
28
25
|
"access": "public"
|
|
@@ -36,10 +33,11 @@
|
|
|
36
33
|
"bugs": {
|
|
37
34
|
"url": "https://github.com/jk2908/mdsrc/issues"
|
|
38
35
|
},
|
|
39
|
-
"description": "A Vite plugin for managing markdown content with type safety",
|
|
40
36
|
"files": [
|
|
41
|
-
"dist
|
|
42
|
-
"
|
|
37
|
+
"dist",
|
|
38
|
+
"README.md",
|
|
39
|
+
"CHANGELOG.md",
|
|
40
|
+
"LICENSE"
|
|
43
41
|
],
|
|
44
42
|
"homepage": "https://github.com/jk2908/mdsrc#readme",
|
|
45
43
|
"keywords": [
|
|
@@ -50,4 +48,4 @@
|
|
|
50
48
|
"frontmatter"
|
|
51
49
|
],
|
|
52
50
|
"license": "MIT"
|
|
53
|
-
}
|
|
51
|
+
}
|