mr-md 1.0.2 → 1.0.4

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.
@@ -14,9 +14,15 @@ function resolveContent(src, options, expectedType = "text") {
14
14
  src.startsWith("/") ||
15
15
  src.startsWith("./") ||
16
16
  src.startsWith("../");
17
- const filePath = path.isAbsolute(src)
17
+ let filePath = path.isAbsolute(src)
18
18
  ? src
19
19
  : path.resolve(options.contentBase ?? ".", src);
20
+ if (!fs.existsSync(filePath) && !path.isAbsolute(src)) {
21
+ const cwdFilePath = path.resolve(process.cwd(), src);
22
+ if (fs.existsSync(cwdFilePath)) {
23
+ filePath = cwdFilePath;
24
+ }
25
+ }
20
26
  if (fs.existsSync(filePath)) {
21
27
  const stat = fs.statSync(filePath);
22
28
  if (stat.isFile()) {
@@ -35,9 +41,15 @@ function resolveAssetSrc(src, options) {
35
41
  const isWebAbsolute = src.startsWith("/") && !fs.existsSync(src);
36
42
  if (isWebAbsolute)
37
43
  return src;
38
- const filePath = path.isAbsolute(src)
44
+ let filePath = path.isAbsolute(src)
39
45
  ? src
40
46
  : path.resolve(options.contentBase ?? ".", src);
47
+ if (!fs.existsSync(filePath) && !path.isAbsolute(src)) {
48
+ const cwdFilePath = path.resolve(process.cwd(), src);
49
+ if (fs.existsSync(cwdFilePath)) {
50
+ filePath = cwdFilePath;
51
+ }
52
+ }
41
53
  if (!fs.existsSync(filePath)) {
42
54
  if (options.strict !== false)
43
55
  throw new Error(`Missing media asset: ${filePath}`);
package/dist/types.d.ts CHANGED
@@ -204,4 +204,13 @@ export interface Chapter {
204
204
  meta: ChapterMeta;
205
205
  lessons: Lesson[];
206
206
  }
207
+ export interface CourseMeta {
208
+ title: string;
209
+ slug: string;
210
+ description?: string;
211
+ }
212
+ export interface Course {
213
+ meta: CourseMeta;
214
+ chapters: Chapter[];
215
+ }
207
216
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,62 +1,62 @@
1
1
  {
2
- "name": "mr-md",
3
- "version": "1.0.2",
4
- "description": "Mr Markdown is an opinionated TypeScript SDK for building interactive, single-file learning pages.",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js",
12
- "default": "./dist/index.js"
13
- }
14
- },
15
- "files": [
16
- "dist",
17
- "src"
18
- ],
19
- "directories": {
20
- "demo": "demo"
21
- },
22
- "scripts": {
23
- "build": "tsc -p tsconfig.build.json && mkdir -p dist/styles dist/client && cp -r src/styles/* dist/styles/ && cp -r src/client/* dist/client/",
24
- "prepublishOnly": "bun run build",
25
- "build:example": "bun demo/demo-1/course.ts",
26
- "serve:example": "bunx serve demo/demo-1/out",
27
- "typecheck": "bunx tsc --noEmit",
28
- "test": "bun test && bun run typecheck",
29
- "test:watch": "bun test --watch",
30
- "lint": "biome lint .",
31
- "format": "biome format --write .",
32
- "check": "biome check --write ."
33
- },
34
- "keywords": [
35
- "markdown",
36
- "blog",
37
- "interactive",
38
- "education",
39
- "shiki",
40
- "katex",
41
- "course"
42
- ],
43
- "author": "Chirayu Chhabra",
44
- "repository": {
45
- "type": "git",
46
- "url": "git+https://github.com/chirayuChhabra/blogkit.git"
47
- },
48
- "license": "ISC",
49
- "devDependencies": {
50
- "@types/katex": "^0.16.8",
51
- "@types/node": "^25.8.0",
52
- "biome": "^0.3.3",
53
- "ts-node": "^10.9.2",
54
- "typescript": "^6.0.3"
55
- },
56
- "dependencies": {
57
- "highlight.js": "^11.11.1",
58
- "katex": "^0.16.47",
59
- "marked": "^18.0.4",
60
- "marked-highlight": "^2.2.4"
61
- }
2
+ "name": "mr-md",
3
+ "version": "1.0.4",
4
+ "description": "Mr Markdown is an opinionated TypeScript SDK for building interactive, single-file learning pages.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "src"
18
+ ],
19
+ "directories": {
20
+ "demo": "demo"
21
+ },
22
+ "scripts": {
23
+ "build": "tsc -p tsconfig.build.json && mkdir -p dist/styles dist/client && cp -r src/styles/* dist/styles/ && cp -r src/client/* dist/client/",
24
+ "prepublishOnly": "bun run build",
25
+ "build:example": "bun demo/src/course.ts",
26
+ "serve:example": "bunx serve demo/out",
27
+ "typecheck": "bunx tsc --noEmit",
28
+ "test": "bun test && bun run typecheck",
29
+ "test:watch": "bun test --watch",
30
+ "lint": "biome lint .",
31
+ "format": "biome format --write .",
32
+ "check": "biome check --write ."
33
+ },
34
+ "keywords": [
35
+ "markdown",
36
+ "blog",
37
+ "interactive",
38
+ "education",
39
+ "shiki",
40
+ "katex",
41
+ "course"
42
+ ],
43
+ "author": "Chirayu Chhabra",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/chirayuChhabra/blogkit.git"
47
+ },
48
+ "license": "ISC",
49
+ "devDependencies": {
50
+ "@types/katex": "^0.16.8",
51
+ "@types/node": "^25.8.0",
52
+ "biome": "^0.3.3",
53
+ "ts-node": "^10.9.2",
54
+ "typescript": "^6.0.3"
55
+ },
56
+ "dependencies": {
57
+ "highlight.js": "^11.11.1",
58
+ "katex": "^0.16.47",
59
+ "marked": "^18.0.4",
60
+ "marked-highlight": "^2.2.4"
61
+ }
62
62
  }
package/src/builder.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as fs from "fs";
2
2
  import * as path from "path";
3
- import { render, renderChapter } from "./renderer/index.js";
3
+ import { render, renderChapter, renderCourse } from "./renderer/index.js";
4
4
  import type {
5
5
  AnimationBlock,
6
6
  AnimationOptions,
@@ -155,21 +155,19 @@ export class LessonBuilder {
155
155
  /** @internal Used by ChapterBuilder to push down shared config */
156
156
  _inheritOptions(parentOpts: BuildOptions, parentRawOpts?: BuildOptions) {
157
157
  this.options = {
158
+ ...this.options,
158
159
  outDir:
159
- this._rawOptions.outDir ?? (parentRawOpts?.outDir || parentOpts.outDir) ?? this.options.outDir,
160
- contentBase:
161
- this._rawOptions.contentBase ??
162
- parentRawOpts?.contentBase ??
163
- this.options.contentBase,
160
+ this._rawOptions.outDir ?? parentOpts.outDir ?? this.options.outDir,
161
+ contentBase: this._rawOptions.contentBase ?? this.options.contentBase,
164
162
  theme: this._rawOptions.theme ?? parentOpts.theme ?? this.options.theme,
165
163
  palette:
166
164
  this._rawOptions.palette ?? parentOpts.palette ?? this.options.palette,
167
165
  strict:
168
166
  this._rawOptions.strict ?? parentOpts.strict ?? this.options.strict,
169
167
  preset: {
168
+ ...this.options.preset,
170
169
  ...parentOpts.preset,
171
170
  ...this._rawOptions.preset,
172
- ...this.options.preset,
173
171
  },
174
172
  };
175
173
  }
@@ -667,6 +665,30 @@ export class ChapterBuilder {
667
665
  return this;
668
666
  }
669
667
 
668
+ /** @internal Used by CourseBuilder to push down shared config */
669
+ _inheritOptions(parentOpts: BuildOptions, parentRawOpts?: BuildOptions) {
670
+ this.options = {
671
+ ...this.options,
672
+ outDir:
673
+ this._rawOptions.outDir ?? parentOpts.outDir ?? this.options.outDir,
674
+ contentBase: this._rawOptions.contentBase ?? this.options.contentBase,
675
+ theme: this._rawOptions.theme ?? parentOpts.theme ?? this.options.theme,
676
+ palette:
677
+ this._rawOptions.palette ?? parentOpts.palette ?? this.options.palette,
678
+ strict:
679
+ this._rawOptions.strict ?? parentOpts.strict ?? this.options.strict,
680
+ preset: {
681
+ ...this.options.preset,
682
+ ...parentOpts.preset,
683
+ ...this._rawOptions.preset,
684
+ },
685
+ };
686
+
687
+ for (const lb of this.lessonBuilders) {
688
+ lb._inheritOptions(this.options, this._rawOptions);
689
+ }
690
+ }
691
+
670
692
  description(text: string): this {
671
693
  this.meta.description = text;
672
694
  return this;
@@ -749,3 +771,83 @@ export function chapter(
749
771
  ): ChapterBuilder {
750
772
  return new ChapterBuilder(title, options, getCallerDir());
751
773
  }
774
+
775
+ // ─── CourseBuilder ──────────────────────────────────────────────────────────
776
+
777
+ export class CourseBuilder {
778
+ private meta: import("./types.js").CourseMeta;
779
+ private chapterBuilders: ChapterBuilder[] = [];
780
+ private options: BuildOptions;
781
+ private _rawOptions: BuildOptions;
782
+
783
+ constructor(title: string, options: BuildOptions = {}, callerDir?: string) {
784
+ this._rawOptions = options;
785
+ let slug = title
786
+ .toLowerCase()
787
+ .replace(/[^a-z0-9]+/g, "-")
788
+ .replace(/(^-|-$)/g, "");
789
+ if (!slug) slug = "course";
790
+
791
+ this.meta = { title, slug };
792
+ this.options = {
793
+ outDir: options.outDir ?? "./out",
794
+ contentBase: options.contentBase ?? callerDir ?? ".",
795
+ theme: options.theme ?? "auto",
796
+ palette: options.palette ?? "ink",
797
+ strict: options.strict ?? true,
798
+ preset: {
799
+ layout: "lesson",
800
+ density: "comfortable",
801
+ tone: "scholarly",
802
+ ...options.preset,
803
+ },
804
+ ...options,
805
+ };
806
+ }
807
+
808
+ slug(slug: string): this {
809
+ this.meta.slug = slug;
810
+ return this;
811
+ }
812
+
813
+ description(text: string): this {
814
+ this.meta.description = text;
815
+ return this;
816
+ }
817
+
818
+ chapter(chapterBuilder: ChapterBuilder): this {
819
+ chapterBuilder._inheritOptions(this.options, this._rawOptions);
820
+ this.chapterBuilders.push(chapterBuilder);
821
+ return this;
822
+ }
823
+
824
+ build(): string {
825
+ const chapters: Chapter[] = [];
826
+ for (const cb of this.chapterBuilders) {
827
+ cb.build();
828
+ chapters.push(cb.toJSON());
829
+ }
830
+
831
+ const courseData: import("./types.js").Course = { meta: this.meta, chapters };
832
+ const html = renderCourse(courseData, this.options);
833
+
834
+ const outDir = path.resolve(this.options.outDir as string);
835
+ if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
836
+
837
+ const outPath = path.join(outDir, `${this.meta.slug}.html`);
838
+ fs.writeFileSync(outPath, html, "utf-8");
839
+
840
+ const relPath = path.relative(process.cwd(), outPath);
841
+ console.log(
842
+ ` ✓ Built course (${this.chapterBuilders.length} chapters) → ${relPath}`,
843
+ );
844
+ return outPath;
845
+ }
846
+ }
847
+
848
+ export function course(
849
+ title: string,
850
+ options: BuildOptions = {},
851
+ ): CourseBuilder {
852
+ return new CourseBuilder(title, options, getCallerDir());
853
+ }
package/src/client/app.js CHANGED
@@ -1,5 +1,5 @@
1
1
  function bkSimDoc(js, props, loop, dependencies) {
2
- const scriptTags = (dependencies || []).map(url => '<script src="' + url.replace(/"/g, '&quot;') + '"></' + 'script>').join("\\n");
2
+ const scriptTags = (dependencies || []).map(url => '<script src="' + url.replace(/"/g, '&quot;') + '"></' + 'script>').join("\n");
3
3
  return (
4
4
  "<!DOCTYPE html><html><head>" +
5
5
  scriptTags +
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { ChapterBuilder, chapter, LessonBuilder, lesson } from "./builder.js";
1
+ export { ChapterBuilder, chapter, CourseBuilder, course, LessonBuilder, lesson } from "./builder.js";
2
2
  export { render } from "./renderer/index.js";
3
3
  export type {
4
4
  AnimationBlock,
@@ -62,8 +62,8 @@ function renderBlockInner(
62
62
  switch (block.type) {
63
63
  case "heading": {
64
64
  const md = resolveContent(block.src, options, "md");
65
- const { html, title } = mdToHtml(md);
66
- const label = block.title || title || (typeof block.src === "string" && !block.src.includes(".md") ? block.src : "Heading");
65
+ const { html, title, headings } = mdToHtml(md);
66
+ const label = block.title || title || headings[0]?.text || (typeof block.src === "string" && !block.src.includes(".md") ? block.src.replace(/^#+\s*/, '') : "Heading");
67
67
  const id = `heading-${idx}`;
68
68
  return {
69
69
  html: `<section id="${id}" class="bk-section bk-heading">${html}</section>`,
@@ -84,8 +84,8 @@ function renderBlockInner(
84
84
 
85
85
  case "section": {
86
86
  const md = resolveContent(block.src, options, "md");
87
- const { html, title } = mdToHtml(md);
88
- const label = block.label || title || (typeof block.src === "string" && !block.src.includes(".md") ? block.src : "Section");
87
+ const { html, title, headings } = mdToHtml(md);
88
+ const label = block.label || title || headings[0]?.text || (typeof block.src === "string" && !block.src.includes(".md") ? block.src.replace(/^#+\s*/, '') : "Section");
89
89
  const id = `section-${idx}`;
90
90
  return {
91
91
  html: `<section id="${id}" class="bk-section bk-subsection">${html}</section>`,
@@ -288,7 +288,8 @@ function renderBlockInner(
288
288
  if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
289
289
  throw new Error("Quiz file not found or invalid JSON format");
290
290
  }
291
- quiz = JSON.parse(trimmed);
291
+ const parsed = JSON.parse(trimmed);
292
+ quiz = Array.isArray(parsed) ? { questions: parsed } : parsed;
292
293
  } catch (e) {
293
294
  const msg = e instanceof Error ? e.message : String(e);
294
295
  if (options.strict !== false) {
@@ -351,7 +352,7 @@ function renderQuestion(q: QuizQuestion, quizId: string, qi: number): string {
351
352
 
352
353
  // Wraps a JS string in a minimal iframe document
353
354
  function iframeDoc(js: string, props: string, loop?: boolean, dependencies?: string[]): string {
354
- const scriptTags = (dependencies ?? []).map((url) => `<script src="${escAttr(url)}"></script>`).join("\\n");
355
+ const scriptTags = (dependencies ?? []).map((url) => `<script src="${escAttr(url)}"></script>`).join("\n");
355
356
  const doc = `<!DOCTYPE html><html><head>
356
357
  ${scriptTags}
357
358
  <style>