@boihendo/skrip 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.
@@ -0,0 +1,5 @@
1
+ export { parseFrontmatter } from './parser.js';
2
+ export { getCollections, getCollection, getItem } from './reader.js';
3
+ export type { ContentItem, Collection, CollectionMeta } from './types.js';
4
+ export type { ParsedContent } from './parser.js';
5
+ //# 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,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AACpE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AACzE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { parseFrontmatter } from './parser.js';
2
+ export { getCollections, getCollection, getItem } from './reader.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,14 @@
1
+ export interface ParsedContent {
2
+ data: Record<string, unknown>;
3
+ content: string;
4
+ }
5
+ /**
6
+ * Parse a markdown string with YAML frontmatter.
7
+ * Returns the parsed frontmatter as `data` and the markdown body as `content`.
8
+ *
9
+ * @example
10
+ * const { data, content } = parseFrontmatter(raw)
11
+ * console.log(data.title) // "My Post"
12
+ */
13
+ export declare function parseFrontmatter(raw: string): ParsedContent;
14
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,OAAO,EAAE,MAAM,CAAA;CAChB;AAkCD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAO3D"}
package/dist/parser.js ADDED
@@ -0,0 +1,56 @@
1
+ function parseValue(str) {
2
+ const s = str.trim();
3
+ if (s === 'true')
4
+ return true;
5
+ if (s === 'false')
6
+ return false;
7
+ if (s === 'null' || s === '~' || s === '')
8
+ return null;
9
+ if (/^-?\d+$/.test(s))
10
+ return parseInt(s, 10);
11
+ if (/^-?\d+\.\d+$/.test(s))
12
+ return parseFloat(s);
13
+ if (s.startsWith('[') && s.endsWith(']')) {
14
+ const inner = s.slice(1, -1).trim();
15
+ if (!inner)
16
+ return [];
17
+ return inner.split(',').map((item) => {
18
+ const t = item.trim();
19
+ return parseValue(t.replace(/^["']|["']$/g, ''));
20
+ });
21
+ }
22
+ return s.replace(/^["']|["']$/g, '');
23
+ }
24
+ function parseYaml(str) {
25
+ const result = {};
26
+ for (const line of str.split('\n')) {
27
+ const trimmed = line.trim();
28
+ if (!trimmed || trimmed.startsWith('#'))
29
+ continue;
30
+ const colonIdx = trimmed.indexOf(':');
31
+ if (colonIdx === -1)
32
+ continue;
33
+ const key = trimmed.slice(0, colonIdx).trim();
34
+ const valueStr = trimmed.slice(colonIdx + 1).trim();
35
+ result[key] = parseValue(valueStr);
36
+ }
37
+ return result;
38
+ }
39
+ /**
40
+ * Parse a markdown string with YAML frontmatter.
41
+ * Returns the parsed frontmatter as `data` and the markdown body as `content`.
42
+ *
43
+ * @example
44
+ * const { data, content } = parseFrontmatter(raw)
45
+ * console.log(data.title) // "My Post"
46
+ */
47
+ export function parseFrontmatter(raw) {
48
+ const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
49
+ if (!match)
50
+ return { data: {}, content: raw.trim() };
51
+ return {
52
+ data: parseYaml(match[1]),
53
+ content: match[2].trim(),
54
+ };
55
+ }
56
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAKA,SAAS,UAAU,CAAC,GAAW;IAC7B,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAA;IACpB,IAAI,CAAC,KAAK,MAAM;QAAE,OAAO,IAAI,CAAA;IAC7B,IAAI,CAAC,KAAK,OAAO;QAAE,OAAO,KAAK,CAAA;IAC/B,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO,IAAI,CAAA;IACtD,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAC7C,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,UAAU,CAAC,CAAC,CAAC,CAAA;IAChD,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QACnC,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,CAAA;QACrB,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACnC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;YACrB,OAAO,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,CAAA;QAClD,CAAC,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAA;AACtC,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,MAAM,MAAM,GAA4B,EAAE,CAAA;IAC1C,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAC3B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAQ;QACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACrC,IAAI,QAAQ,KAAK,CAAC,CAAC;YAAE,SAAQ;QAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAA;QAC7C,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QACnD,MAAM,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAA;IACpC,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAA;IACtE,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,CAAA;IACpD,OAAO;QACL,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;KACzB,CAAA;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { ContentItem, Collection, CollectionMeta } from './types.js';
2
+ /**
3
+ * List all collections (subdirectories containing .md files) in the content directory.
4
+ */
5
+ export declare function getCollections(contentDir?: string): Promise<CollectionMeta[]>;
6
+ /**
7
+ * Get all items in a collection, sorted alphabetically by slug.
8
+ */
9
+ export declare function getCollection(name: string, contentDir?: string): Promise<Collection | null>;
10
+ /**
11
+ * Get a single content item by collection name and slug.
12
+ */
13
+ export declare function getItem(collection: string, slug: string, contentDir?: string): Promise<ContentItem | null>;
14
+ //# sourceMappingURL=reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../src/reader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAMzE;;GAEG;AACH,wBAAsB,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAgBnF;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAiBjG;AAED;;GAEG;AACH,wBAAsB,OAAO,CAC3B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAU7B"}
package/dist/reader.js ADDED
@@ -0,0 +1,61 @@
1
+ import { promises as fs } from 'fs';
2
+ import path from 'path';
3
+ import { parseFrontmatter } from './parser.js';
4
+ function resolveContentDir(contentDir) {
5
+ return contentDir ?? path.join(process.cwd(), 'content');
6
+ }
7
+ /**
8
+ * List all collections (subdirectories containing .md files) in the content directory.
9
+ */
10
+ export async function getCollections(contentDir) {
11
+ const dir = resolveContentDir(contentDir);
12
+ try {
13
+ const entries = await fs.readdir(dir, { withFileTypes: true });
14
+ const metas = await Promise.all(entries
15
+ .filter((e) => e.isDirectory())
16
+ .map(async (d) => {
17
+ const files = await fs.readdir(path.join(dir, d.name));
18
+ return { name: d.name, count: files.filter((f) => f.endsWith('.md')).length };
19
+ }));
20
+ return metas.filter((m) => m.count > 0);
21
+ }
22
+ catch {
23
+ return [];
24
+ }
25
+ }
26
+ /**
27
+ * Get all items in a collection, sorted alphabetically by slug.
28
+ */
29
+ export async function getCollection(name, contentDir) {
30
+ const dir = resolveContentDir(contentDir);
31
+ const collectionDir = path.join(dir, name);
32
+ try {
33
+ const files = (await fs.readdir(collectionDir)).filter((f) => f.endsWith('.md')).sort();
34
+ const items = await Promise.all(files.map(async (file) => {
35
+ const slug = file.replace(/\.md$/, '');
36
+ const raw = await fs.readFile(path.join(collectionDir, file), 'utf-8');
37
+ const { data, content } = parseFrontmatter(raw);
38
+ return { slug, collection: name, data, content, raw };
39
+ }));
40
+ return { name, count: items.length, items };
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ }
46
+ /**
47
+ * Get a single content item by collection name and slug.
48
+ */
49
+ export async function getItem(collection, slug, contentDir) {
50
+ const dir = resolveContentDir(contentDir);
51
+ const filePath = path.join(dir, collection, `${slug}.md`);
52
+ try {
53
+ const raw = await fs.readFile(filePath, 'utf-8');
54
+ const { data, content } = parseFrontmatter(raw);
55
+ return { slug, collection, data, content, raw };
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ }
61
+ //# sourceMappingURL=reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.js","sourceRoot":"","sources":["../src/reader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export interface ContentItem {
2
+ slug: string;
3
+ collection: string;
4
+ data: Record<string, unknown>;
5
+ content: string;
6
+ raw: string;
7
+ }
8
+ export interface CollectionMeta {
9
+ name: string;
10
+ count: number;
11
+ }
12
+ export interface Collection {
13
+ name: string;
14
+ count: number;
15
+ items: ContentItem[];
16
+ }
17
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,WAAW,EAAE,CAAA;CACrB"}
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,38 @@
1
+ {
2
+ "name": "@boihendo/skrip",
3
+ "version": "0.1.0",
4
+ "description": "Lightweight headless CMS powered by markdown files",
5
+ "license": "MIT",
6
+ "author": "",
7
+ "keywords": [
8
+ "cms",
9
+ "markdown",
10
+ "headless",
11
+ "content",
12
+ "frontmatter",
13
+ "static"
14
+ ],
15
+ "type": "module",
16
+ "main": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "import": "./dist/index.js",
21
+ "types": "./dist/index.d.ts"
22
+ }
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "README.md"
27
+ ],
28
+ "scripts": {
29
+ "build": "tsc",
30
+ "prepublishOnly": "npm run build"
31
+ },
32
+ "engines": {
33
+ "node": ">=18"
34
+ },
35
+ "devDependencies": {
36
+ "typescript": "^5"
37
+ }
38
+ }