@contedra/md-importer 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 contedra
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # @contedra/md-importer
2
+
3
+ CLI tool and library to import YAML-frontmatter Markdown files (with images) into Firestore, using Conteditor model definition JSON for schema validation.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @contedra/md-importer
9
+ ```
10
+
11
+ ## CLI Usage
12
+
13
+ ```bash
14
+ npx @contedra/md-importer \
15
+ --md-dir ./content \
16
+ --model ./models/blog_posts.json \
17
+ --project-id your-project-id \
18
+ --credential ./service-account.json
19
+ ```
20
+
21
+ ### CLI Options
22
+
23
+ | Option | Required | Description |
24
+ |--------|----------|-------------|
25
+ | `--md-dir <path>` | Yes | Directory containing `.md` files |
26
+ | `--model <path>` | Yes | Path to model definition JSON |
27
+ | `--project-id <id>` | Yes | Firebase project ID |
28
+ | `--credential <path>` | No | Path to service account JSON (uses ADC if omitted) |
29
+ | `--collection <name>` | No | Firestore collection name (defaults to `modelName`) |
30
+ | `--field-mapping <json>` | No | JSON mapping frontmatter keys to model properties |
31
+
32
+ ### Field Mapping
33
+
34
+ When your Markdown frontmatter keys don't match the model property names, use `--field-mapping`:
35
+
36
+ ```bash
37
+ npx @contedra/md-importer \
38
+ --md-dir ./content \
39
+ --model ./models/blog_posts.json \
40
+ --project-id your-project-id \
41
+ --field-mapping '{"article_title":"title","article_date":"publishedAt"}'
42
+ ```
43
+
44
+ Unmapped frontmatter keys that match model property names are auto-matched.
45
+
46
+ ## Programmatic API
47
+
48
+ ### `mdImporter(config): Promise<ImportResult>`
49
+
50
+ ```typescript
51
+ import { mdImporter } from "@contedra/md-importer";
52
+
53
+ const result = await mdImporter({
54
+ mdDir: "./content",
55
+ modelFile: "./models/blog_posts.json",
56
+ firebaseConfig: {
57
+ projectId: "your-project-id",
58
+ credential: "./service-account.json",
59
+ },
60
+ fieldMapping: {
61
+ article_title: "title",
62
+ article_date: "publishedAt",
63
+ },
64
+ });
65
+
66
+ console.log(`Imported: ${result.imported.length}`);
67
+ console.log(`Errors: ${result.errors.length}`);
68
+ ```
69
+
70
+ ### Custom Image Resolver
71
+
72
+ By default, local images referenced in Markdown are read from the filesystem and uploaded to Firebase Storage (`assets/{modelName}/{contentId}/{fileName}`). Provide a custom resolver to change this behavior:
73
+
74
+ ```typescript
75
+ const result = await mdImporter({
76
+ mdDir: "./content",
77
+ modelFile: "./models/blog_posts.json",
78
+ firebaseConfig: { projectId: "your-project-id" },
79
+ resolveImage: async (imagePath, mdFilePath) => {
80
+ const response = await fetch(`https://cdn.example.com/${imagePath}`);
81
+ return Buffer.from(await response.arrayBuffer());
82
+ },
83
+ });
84
+ ```
85
+
86
+ ### Helper Functions
87
+
88
+ - `generateDocId(filePath)` — Converts a filename to a slugified Firestore document ID
89
+ - `parseMarkdownFile(filePath)` — Parses a `.md` file into `{ frontmatter, body }`
90
+ - `parseMarkdownString(content)` — Parses a markdown string (uses gray-matter)
91
+ - `mapFields(frontmatter, model, fieldMapping?)` — Maps frontmatter fields to model properties, returns `{ data, unmapped }`
92
+
93
+ ## Image Handling
94
+
95
+ Images referenced in Markdown (e.g., `![alt](./images/photo.png)`) are:
96
+
97
+ 1. Extracted from the markdown body
98
+ 2. Resolved via the local filesystem (or custom `resolveImage`)
99
+ 3. Uploaded to Firebase Storage at `assets/{modelName}/{contentId}/{fileName}`
100
+ 4. Replaced in the markdown body with `asset://` URIs
101
+
102
+ External URLs (`http://`, `https://`) and `asset://` URIs are skipped.
103
+
104
+ ## License
105
+
106
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { mdImporter } from "./importer.js";
4
+ const program = new Command();
5
+ program
6
+ .name("md-importer")
7
+ .description("Import YAML-frontmatter Markdown files + images into Firestore")
8
+ .requiredOption("--md-dir <path>", "Directory containing .md files")
9
+ .requiredOption("--model <path>", "Path to model definition JSON")
10
+ .requiredOption("--project-id <id>", "Firebase project ID")
11
+ .option("--credential <path>", "Path to service account JSON")
12
+ .option("--collection <name>", "Firestore collection name (defaults to modelName)")
13
+ .option("--field-mapping <json>", "JSON object mapping frontmatter keys to model property names")
14
+ .action(async (opts) => {
15
+ const fieldMapping = opts.fieldMapping
16
+ ? JSON.parse(opts.fieldMapping)
17
+ : undefined;
18
+ const result = await mdImporter({
19
+ mdDir: opts.mdDir,
20
+ modelFile: opts.model,
21
+ firebaseConfig: {
22
+ projectId: opts.projectId,
23
+ credential: opts.credential,
24
+ },
25
+ collection: opts.collection,
26
+ fieldMapping,
27
+ });
28
+ console.log(`Imported ${result.imported.length} file(s) successfully.`);
29
+ if (result.errors.length > 0) {
30
+ console.error(`Failed to import ${result.errors.length} file(s):`);
31
+ for (const err of result.errors) {
32
+ console.error(` ${err.filePath}: ${err.error}`);
33
+ }
34
+ process.exit(1);
35
+ }
36
+ });
37
+ program.parse();
38
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,aAAa,CAAC;KACnB,WAAW,CACV,gEAAgE,CACjE;KACA,cAAc,CAAC,iBAAiB,EAAE,gCAAgC,CAAC;KACnE,cAAc,CAAC,gBAAgB,EAAE,+BAA+B,CAAC;KACjE,cAAc,CAAC,mBAAmB,EAAE,qBAAqB,CAAC;KAC1D,MAAM,CAAC,qBAAqB,EAAE,8BAA8B,CAAC;KAC7D,MAAM,CAAC,qBAAqB,EAAE,mDAAmD,CAAC;KAClF,MAAM,CACL,wBAAwB,EACxB,8DAA8D,CAC/D;KACA,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY;QACpC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAA4B;QAC3D,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC;QAC9B,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,SAAS,EAAE,IAAI,CAAC,KAAK;QACrB,cAAc,EAAE;YACd,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B;QACD,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,YAAY;KACb,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CACT,YAAY,MAAM,CAAC,QAAQ,CAAC,MAAM,wBAAwB,CAC3D,CAAC;IAEF,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,KAAK,CAAC,oBAAoB,MAAM,CAAC,MAAM,CAAC,MAAM,WAAW,CAAC,CAAC;QACnE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAChC,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QACnD,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,32 @@
1
+ export interface ImageRef {
2
+ /** Full match string in the Markdown */
3
+ fullMatch: string;
4
+ /** Alt text */
5
+ alt: string;
6
+ /** Original image path from Markdown */
7
+ originalPath: string;
8
+ }
9
+ /**
10
+ * Extract all image references from Markdown content.
11
+ * Skips URLs (http:// or https://) and asset:// references.
12
+ */
13
+ export declare function extractImageRefs(body: string): ImageRef[];
14
+ /**
15
+ * Default image resolver: reads file relative to the Markdown file's directory.
16
+ */
17
+ export declare function defaultResolveImage(imagePath: string, mdFilePath: string): Promise<Buffer>;
18
+ /**
19
+ * Generate a Storage path for an asset using v2 format.
20
+ * Format: assets/{modelName}/{contentId}/{fileId}
21
+ */
22
+ export declare function assetStoragePath(modelName: string, contentId: string, fileName: string): string;
23
+ /**
24
+ * Generate an asset:// URI using v2 format.
25
+ * Format: asset://{modelName}/{contentId}/{fileId}
26
+ */
27
+ export declare function assetUri(modelName: string, contentId: string, fileName: string): string;
28
+ /**
29
+ * Replace image references in Markdown body with asset:// URIs.
30
+ */
31
+ export declare function replaceImageRefs(body: string, replacements: Map<string, string>): string;
32
+ //# sourceMappingURL=images.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"images.d.ts","sourceRoot":"","sources":["../src/images.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,QAAQ;IACvB,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,wCAAwC;IACxC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CAkBzD;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,MAAM,CAER;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CACtB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,MAAM,CAER;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,MAAM,CAMR"}
package/dist/images.js ADDED
@@ -0,0 +1,58 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ /** Regex matching Markdown image syntax: ![alt](path) */
4
+ const IMAGE_REGEX = /!\[([^\]]*)\]\(([^)]+)\)/g;
5
+ /**
6
+ * Extract all image references from Markdown content.
7
+ * Skips URLs (http:// or https://) and asset:// references.
8
+ */
9
+ export function extractImageRefs(body) {
10
+ const refs = [];
11
+ for (const match of body.matchAll(IMAGE_REGEX)) {
12
+ const imgPath = match[2];
13
+ if (imgPath.startsWith("http://") ||
14
+ imgPath.startsWith("https://") ||
15
+ imgPath.startsWith("asset://")) {
16
+ continue;
17
+ }
18
+ refs.push({
19
+ fullMatch: match[0],
20
+ alt: match[1],
21
+ originalPath: imgPath,
22
+ });
23
+ }
24
+ return refs;
25
+ }
26
+ /**
27
+ * Default image resolver: reads file relative to the Markdown file's directory.
28
+ */
29
+ export async function defaultResolveImage(imagePath, mdFilePath) {
30
+ const dir = path.dirname(mdFilePath);
31
+ const resolved = path.resolve(dir, imagePath);
32
+ return readFile(resolved);
33
+ }
34
+ /**
35
+ * Generate a Storage path for an asset using v2 format.
36
+ * Format: assets/{modelName}/{contentId}/{fileId}
37
+ */
38
+ export function assetStoragePath(modelName, contentId, fileName) {
39
+ return `assets/${modelName}/${contentId}/${fileName}`;
40
+ }
41
+ /**
42
+ * Generate an asset:// URI using v2 format.
43
+ * Format: asset://{modelName}/{contentId}/{fileId}
44
+ */
45
+ export function assetUri(modelName, contentId, fileName) {
46
+ return `asset://${modelName}/${contentId}/${fileName}`;
47
+ }
48
+ /**
49
+ * Replace image references in Markdown body with asset:// URIs.
50
+ */
51
+ export function replaceImageRefs(body, replacements) {
52
+ let result = body;
53
+ for (const [fullMatch, assetUriStr] of replacements) {
54
+ result = result.replace(fullMatch, assetUriStr);
55
+ }
56
+ return result;
57
+ }
58
+ //# sourceMappingURL=images.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"images.js","sourceRoot":"","sources":["../src/images.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,yDAAyD;AACzD,MAAM,WAAW,GAAG,2BAA2B,CAAC;AAWhD;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,IAAI,GAAe,EAAE,CAAC;IAC5B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/C,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,IACE,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC;YAC7B,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC;YAC9B,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,EAC9B,CAAC;YACD,SAAS;QACX,CAAC;QACD,IAAI,CAAC,IAAI,CAAC;YACR,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;YACnB,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;YACb,YAAY,EAAE,OAAO;SACtB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,SAAiB,EACjB,UAAkB;IAElB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC9C,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,SAAiB,EACjB,SAAiB,EACjB,QAAgB;IAEhB,OAAO,UAAU,SAAS,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;AACxD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CACtB,SAAiB,EACjB,SAAiB,EACjB,QAAgB;IAEhB,OAAO,WAAW,SAAS,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;AACzD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAAY,EACZ,YAAiC;IAEjC,IAAI,MAAM,GAAG,IAAI,CAAC;IAClB,KAAK,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,YAAY,EAAE,CAAC;QACpD,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { MdImporterConfig, ImportResult } from "./types.js";
2
+ /**
3
+ * Generate a document ID from a filename.
4
+ * Uses the filename stem, slugified for safe Firestore doc IDs.
5
+ */
6
+ export declare function generateDocId(filePath: string): string;
7
+ /**
8
+ * Import Markdown files into Firestore using a model definition.
9
+ */
10
+ export declare function mdImporter(config: MdImporterConfig): Promise<ImportResult>;
11
+ //# sourceMappingURL=importer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"importer.d.ts","sourceRoot":"","sources":["../src/importer.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAWjE;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,YAAY,CAAC,CAkFvB"}
@@ -0,0 +1,88 @@
1
+ import { readdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { loadModel, detectBodyField, initFirestore } from "@contedra/core";
4
+ import { getStorage } from "firebase-admin/storage";
5
+ import { getApps } from "firebase-admin/app";
6
+ import slugify from "slugify";
7
+ import { parseMarkdownFile } from "./parser.js";
8
+ import { mapFields } from "./mapper.js";
9
+ import { extractImageRefs, defaultResolveImage, assetStoragePath, assetUri, replaceImageRefs, } from "./images.js";
10
+ /**
11
+ * Generate a document ID from a filename.
12
+ * Uses the filename stem, slugified for safe Firestore doc IDs.
13
+ */
14
+ export function generateDocId(filePath) {
15
+ const stem = path.basename(filePath, path.extname(filePath));
16
+ return slugify(stem, { lower: true, strict: true });
17
+ }
18
+ /**
19
+ * Import Markdown files into Firestore using a model definition.
20
+ */
21
+ export async function mdImporter(config) {
22
+ const model = await loadModel(config.modelFile);
23
+ const bodyField = detectBodyField(model);
24
+ const collectionName = config.collection ?? model.modelName;
25
+ const resolveImage = config.resolveImage ?? defaultResolveImage;
26
+ const firestore = initFirestore(config.firebaseConfig);
27
+ const appName = `contedra-${config.firebaseConfig.projectId}`;
28
+ const app = getApps().find((a) => a.name === appName);
29
+ const bucket = getStorage(app).bucket();
30
+ const mdFiles = await findMarkdownFiles(config.mdDir);
31
+ const result = { imported: [], errors: [] };
32
+ for (const mdFile of mdFiles) {
33
+ try {
34
+ const absolutePath = path.resolve(config.mdDir, mdFile);
35
+ const docId = generateDocId(mdFile);
36
+ const { frontmatter, body } = await parseMarkdownFile(absolutePath);
37
+ const { data } = mapFields(frontmatter, model, config.fieldMapping);
38
+ let processedBody = body;
39
+ // Process images
40
+ if (bodyField && body) {
41
+ const imageRefs = extractImageRefs(body);
42
+ const replacements = new Map();
43
+ for (const ref of imageRefs) {
44
+ const fileName = path.basename(ref.originalPath);
45
+ const storagePath = assetStoragePath(model.modelName, docId, fileName);
46
+ const imageBuffer = await resolveImage(ref.originalPath, absolutePath);
47
+ const file = bucket.file(storagePath);
48
+ await file.save(imageBuffer);
49
+ const uri = assetUri(model.modelName, docId, fileName);
50
+ replacements.set(ref.fullMatch, `![${ref.alt}](${uri})`);
51
+ }
52
+ processedBody = replaceImageRefs(body, replacements);
53
+ }
54
+ // Build the Firestore document
55
+ const docData = { ...data };
56
+ if (bodyField) {
57
+ docData[bodyField] = processedBody;
58
+ }
59
+ // Convert Date objects to Firestore Timestamps
60
+ const { Timestamp } = await import("firebase-admin/firestore");
61
+ for (const [key, value] of Object.entries(docData)) {
62
+ if (value instanceof Date) {
63
+ docData[key] = Timestamp.fromDate(value);
64
+ }
65
+ }
66
+ await firestore.collection(collectionName).doc(docId).set(docData);
67
+ result.imported.push({ docId, filePath: mdFile });
68
+ }
69
+ catch (err) {
70
+ result.errors.push({
71
+ filePath: mdFile,
72
+ error: err instanceof Error ? err.message : String(err),
73
+ });
74
+ }
75
+ }
76
+ return result;
77
+ }
78
+ async function findMarkdownFiles(dir) {
79
+ const entries = await readdir(dir, { withFileTypes: true });
80
+ const mdFiles = [];
81
+ for (const entry of entries) {
82
+ if (entry.isFile() && entry.name.endsWith(".md")) {
83
+ mdFiles.push(entry.name);
84
+ }
85
+ }
86
+ return mdFiles.sort();
87
+ }
88
+ //# sourceMappingURL=importer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"importer.js","sourceRoot":"","sources":["../src/importer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { mdImporter } from "./importer.js";
2
+ export { generateDocId } from "./importer.js";
3
+ export { parseMarkdownFile, parseMarkdownString } from "./parser.js";
4
+ export { mapFields } from "./mapper.js";
5
+ export { extractImageRefs, defaultResolveImage, assetStoragePath, assetUri, replaceImageRefs, } from "./images.js";
6
+ export type { MdImporterConfig, ImportResult, ImportedDocument, } from "./types.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,QAAQ,EACR,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { mdImporter } from "./importer.js";
2
+ export { generateDocId } from "./importer.js";
3
+ export { parseMarkdownFile, parseMarkdownString } from "./parser.js";
4
+ export { mapFields } from "./mapper.js";
5
+ export { extractImageRefs, defaultResolveImage, assetStoragePath, assetUri, replaceImageRefs, } from "./images.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,QAAQ,EACR,gBAAgB,GACjB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ModelDefinition } from "@contedra/core";
2
+ export interface MappedFields {
3
+ data: Record<string, unknown>;
4
+ unmapped: string[];
5
+ }
6
+ /**
7
+ * Map frontmatter fields to model properties.
8
+ * 1. Apply explicit fieldMapping (frontmatter key -> model property name)
9
+ * 2. Auto-match remaining frontmatter keys by name equality with model properties
10
+ */
11
+ export declare function mapFields(frontmatter: Record<string, unknown>, model: ModelDefinition, fieldMapping?: Record<string, string>): MappedFields;
12
+ //# sourceMappingURL=mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapper.d.ts","sourceRoot":"","sources":["../src/mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,gBAAgB,CAAC;AAErE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,KAAK,EAAE,eAAe,EACtB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACpC,YAAY,CAyCd"}
package/dist/mapper.js ADDED
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Map frontmatter fields to model properties.
3
+ * 1. Apply explicit fieldMapping (frontmatter key -> model property name)
4
+ * 2. Auto-match remaining frontmatter keys by name equality with model properties
5
+ */
6
+ export function mapFields(frontmatter, model, fieldMapping) {
7
+ const data = {};
8
+ const unmapped = [];
9
+ const propertyNames = new Set(model.properties.map((p) => p.propertyName));
10
+ const resolvedMapping = new Map();
11
+ // Build explicit mapping
12
+ if (fieldMapping) {
13
+ for (const [fmKey, propName] of Object.entries(fieldMapping)) {
14
+ resolvedMapping.set(fmKey, propName);
15
+ }
16
+ }
17
+ // Auto-match remaining keys
18
+ for (const fmKey of Object.keys(frontmatter)) {
19
+ if (!resolvedMapping.has(fmKey) && propertyNames.has(fmKey)) {
20
+ resolvedMapping.set(fmKey, fmKey);
21
+ }
22
+ }
23
+ for (const [fmKey, propName] of resolvedMapping) {
24
+ if (fmKey in frontmatter && propertyNames.has(propName)) {
25
+ const prop = model.properties.find((p) => p.propertyName === propName);
26
+ data[propName] = coerceValue(frontmatter[fmKey], prop);
27
+ }
28
+ }
29
+ // Identify unmapped frontmatter keys
30
+ for (const fmKey of Object.keys(frontmatter)) {
31
+ if (!resolvedMapping.has(fmKey)) {
32
+ unmapped.push(fmKey);
33
+ }
34
+ }
35
+ return { data, unmapped };
36
+ }
37
+ function coerceValue(value, prop) {
38
+ if (value == null)
39
+ return undefined;
40
+ switch (prop.dataType) {
41
+ case "datetime":
42
+ if (value instanceof Date)
43
+ return value;
44
+ if (typeof value === "string" || typeof value === "number") {
45
+ return new Date(value);
46
+ }
47
+ return value;
48
+ case "relatedMany":
49
+ if (Array.isArray(value))
50
+ return value.map(String);
51
+ return [String(value)];
52
+ case "relatedOne":
53
+ return String(value);
54
+ default:
55
+ return value;
56
+ }
57
+ }
58
+ //# sourceMappingURL=mapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapper.js","sourceRoot":"","sources":["../src/mapper.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,MAAM,UAAU,SAAS,CACvB,WAAoC,EACpC,KAAsB,EACtB,YAAqC;IAErC,MAAM,IAAI,GAA4B,EAAE,CAAC;IACzC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,MAAM,aAAa,GAAG,IAAI,GAAG,CAC3B,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAC5C,CAAC;IAEF,MAAM,eAAe,GAAG,IAAI,GAAG,EAAkB,CAAC;IAElD,yBAAyB;IACzB,IAAI,YAAY,EAAE,CAAC;QACjB,KAAK,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7D,eAAe,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,4BAA4B;IAC5B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7C,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5D,eAAe,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,eAAe,EAAE,CAAC;QAChD,IAAI,KAAK,IAAI,WAAW,IAAI,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxD,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAChC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,QAAQ,CAClB,CAAC;YACnB,IAAI,CAAC,QAAQ,CAAC,GAAG,WAAW,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAED,qCAAqC;IACrC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7C,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAChC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,WAAW,CAAC,KAAc,EAAE,IAAmB;IACtD,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,SAAS,CAAC;IAEpC,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;QACtB,KAAK,UAAU;YACb,IAAI,KAAK,YAAY,IAAI;gBAAE,OAAO,KAAK,CAAC;YACxC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC3D,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;YACzB,CAAC;YACD,OAAO,KAAK,CAAC;QACf,KAAK,aAAa;YAChB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACnD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACzB,KAAK,YAAY;YACf,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;QACvB;YACE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ export interface ParsedMarkdown {
2
+ frontmatter: Record<string, unknown>;
3
+ body: string;
4
+ }
5
+ export declare function parseMarkdownFile(filePath: string): Promise<ParsedMarkdown>;
6
+ export declare function parseMarkdownString(content: string): ParsedMarkdown;
7
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,CAAC,CAGzB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAGnE"}
package/dist/parser.js ADDED
@@ -0,0 +1,11 @@
1
+ import matter from "gray-matter";
2
+ import { readFile } from "node:fs/promises";
3
+ export async function parseMarkdownFile(filePath) {
4
+ const raw = await readFile(filePath, "utf-8");
5
+ return parseMarkdownString(raw);
6
+ }
7
+ export function parseMarkdownString(content) {
8
+ const { data, content: body } = matter(content);
9
+ return { frontmatter: data, body: body.trim() };
10
+ }
11
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAO5C,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAAgB;IAEhB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9C,OAAO,mBAAmB,CAAC,GAAG,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAChD,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;AAClD,CAAC"}
@@ -0,0 +1,27 @@
1
+ import type { FirebaseConfig } from "@contedra/core";
2
+ export interface MdImporterConfig {
3
+ /** Directory containing .md files to import */
4
+ mdDir: string;
5
+ /** Path to model definition JSON file */
6
+ modelFile: string;
7
+ /** Firebase configuration */
8
+ firebaseConfig: FirebaseConfig;
9
+ /** Firestore collection name (defaults to model's modelName) */
10
+ collection?: string;
11
+ /** Mapping from frontmatter keys to model property names */
12
+ fieldMapping?: Record<string, string>;
13
+ /** Custom image resolver. Default: reads relative to the .md file */
14
+ resolveImage?: (imagePath: string, mdFilePath: string) => Promise<Buffer>;
15
+ }
16
+ export interface ImportedDocument {
17
+ docId: string;
18
+ filePath: string;
19
+ }
20
+ export interface ImportResult {
21
+ imported: ImportedDocument[];
22
+ errors: Array<{
23
+ filePath: string;
24
+ error: string;
25
+ }>;
26
+ }
27
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,WAAW,gBAAgB;IAC/B,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,cAAc,EAAE,cAAc,CAAC;IAC/B,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qEAAqE;IACrE,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3E;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,MAAM,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@contedra/md-importer",
3
+ "version": "0.1.0",
4
+ "description": "CLI tool to import YAML-frontmatter Markdown files + images into Firestore using model definition JSON",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "md-importer": "./dist/cli.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "keywords": [
21
+ "conteditor",
22
+ "firestore",
23
+ "firebase",
24
+ "markdown",
25
+ "importer",
26
+ "cli"
27
+ ],
28
+ "author": "Contedra",
29
+ "license": "MIT",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/contedra/toolkit",
33
+ "directory": "packages/md-importer"
34
+ },
35
+ "dependencies": {
36
+ "commander": "^13.0.0",
37
+ "firebase-admin": "^13.0.0",
38
+ "gray-matter": "^4.0.3",
39
+ "slugify": "^1.6.6",
40
+ "@contedra/core": "0.1.0"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^22.0.0",
44
+ "oxlint": "^1.57.0",
45
+ "typescript": "^5.7.0",
46
+ "vitest": "^3.0.0"
47
+ },
48
+ "scripts": {
49
+ "build": "tsc",
50
+ "test": "vitest run",
51
+ "test:integration": "vitest run --config vitest.integration.config.ts",
52
+ "lint": "oxlint src"
53
+ }
54
+ }