plainb 1.1.0 → 1.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/README.md CHANGED
@@ -133,7 +133,7 @@ type Cell = CodeCell | MarkdownCell | RawCell
133
133
  ## Demo
134
134
 
135
135
  ```sh
136
- git clone https://github.com/trungleduc/plainb
136
+ git clone https://github.com/notebook-link/plainb
137
137
  cd plainb
138
138
  npm install
139
139
  npm run demo
package/dist/index.d.ts CHANGED
@@ -4,6 +4,11 @@ export * from "./parseClassicMd";
4
4
  export * from "./parseMystMd";
5
5
  export * from "./parseSphinxGallery";
6
6
  export * from "./notebook";
7
+ export * from "./toPy";
8
+ export * from "./toClassicMd";
9
+ export * from "./toMystMd";
10
+ export * from "./toSphinxGallery";
7
11
  import type { Notebook } from "./notebook";
8
12
  export declare function parse(text: string, format: "py" | "md" | "sphinx-gallery"): Notebook;
13
+ export declare function serialize(notebook: Notebook, format: "py" | "md" | "sphinx-gallery"): string;
9
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAK3B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,gBAAgB,GAAG,QAAQ,CAKpF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAQlC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,gBAAgB,GAAG,QAAQ,CAKpF;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,gBAAgB,GAAG,MAAM,CAK5F"}
package/dist/index.js CHANGED
@@ -4,9 +4,16 @@ export * from "./parseClassicMd";
4
4
  export * from "./parseMystMd";
5
5
  export * from "./parseSphinxGallery";
6
6
  export * from "./notebook";
7
+ export * from "./toPy";
8
+ export * from "./toClassicMd";
9
+ export * from "./toMystMd";
10
+ export * from "./toSphinxGallery";
7
11
  import { parsePy } from "./parsePy";
8
12
  import { parseMd } from "./parseMd";
9
13
  import { parseSphinxGallery } from "./parseSphinxGallery";
14
+ import { toPy } from "./toPy";
15
+ import { toMystMd } from "./toMystMd";
16
+ import { toSphinxGallery } from "./toSphinxGallery";
10
17
  export function parse(text, format) {
11
18
  if (format === "py")
12
19
  return parsePy(text);
@@ -16,4 +23,13 @@ export function parse(text, format) {
16
23
  return parseSphinxGallery(text);
17
24
  throw new Error(`Unknown format: "${format}". Expected "py", "md", or "sphinx-gallery".`);
18
25
  }
26
+ export function serialize(notebook, format) {
27
+ if (format === "py")
28
+ return toPy(notebook);
29
+ if (format === "md")
30
+ return toMystMd(notebook);
31
+ if (format === "sphinx-gallery")
32
+ return toSphinxGallery(notebook);
33
+ throw new Error(`Unknown format: "${format}". Expected "py", "md", or "sphinx-gallery".`);
34
+ }
19
35
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAE3B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAG1D,MAAM,UAAU,KAAK,CAAC,IAAY,EAAE,MAAsC;IACxE,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,MAAM,KAAK,gBAAgB;QAAE,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACjE,MAAM,IAAI,KAAK,CAAC,oBAAoB,MAAM,8CAA8C,CAAC,CAAC;AAC5F,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAElC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpD,MAAM,UAAU,KAAK,CAAC,IAAY,EAAE,MAAsC;IACxE,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,MAAM,KAAK,gBAAgB;QAAE,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACjE,MAAM,IAAI,KAAK,CAAC,oBAAoB,MAAM,8CAA8C,CAAC,CAAC;AAC5F,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAkB,EAAE,MAAsC;IAClF,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC/C,IAAI,MAAM,KAAK,gBAAgB;QAAE,OAAO,eAAe,CAAC,QAAQ,CAAC,CAAC;IAClE,MAAM,IAAI,KAAK,CAAC,oBAAoB,MAAM,8CAA8C,CAAC,CAAC;AAC5F,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { Notebook } from "./notebook";
2
+ /**
3
+ * Serialize a `Notebook` to classic Markdown format.
4
+ *
5
+ * - Markdown cells → raw text
6
+ * - Code cells → fenced code block (`` ```language ```)
7
+ * - Raw cells are omitted (no representation in classic Markdown)
8
+ *
9
+ * Cell metadata is not preserved — the classic format carries no metadata.
10
+ *
11
+ * @param language Fence language tag for code cells. Defaults to `"python"`.
12
+ */
13
+ export declare function toClassicMd(notebook: Notebook, language?: string): string;
14
+ //# sourceMappingURL=toClassicMd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toClassicMd.d.ts","sourceRoot":"","sources":["../src/toClassicMd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAU3C;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,SAAW,GAAG,MAAM,CAe3E"}
@@ -0,0 +1,34 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Notebook → Classic Markdown serializer
3
+ // ---------------------------------------------------------------------------
4
+ function joinSource(source) {
5
+ return source.join("");
6
+ }
7
+ /**
8
+ * Serialize a `Notebook` to classic Markdown format.
9
+ *
10
+ * - Markdown cells → raw text
11
+ * - Code cells → fenced code block (`` ```language ```)
12
+ * - Raw cells are omitted (no representation in classic Markdown)
13
+ *
14
+ * Cell metadata is not preserved — the classic format carries no metadata.
15
+ *
16
+ * @param language Fence language tag for code cells. Defaults to `"python"`.
17
+ */
18
+ export function toClassicMd(notebook, language = "python") {
19
+ const parts = [];
20
+ for (const cell of notebook.cells) {
21
+ if (cell.cell_type === "markdown") {
22
+ const src = joinSource(cell.source);
23
+ if (src)
24
+ parts.push(src);
25
+ }
26
+ else if (cell.cell_type === "code") {
27
+ const src = joinSource(cell.source);
28
+ parts.push(`\`\`\`${language}\n${src}\n\`\`\``);
29
+ }
30
+ // raw cells: no representation in classic Markdown
31
+ }
32
+ return parts.join("\n\n") + "\n";
33
+ }
34
+ //# sourceMappingURL=toClassicMd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toClassicMd.js","sourceRoot":"","sources":["../src/toClassicMd.ts"],"names":[],"mappings":"AAEA,8EAA8E;AAC9E,yCAAyC;AACzC,8EAA8E;AAE9E,SAAS,UAAU,CAAC,MAAgB;IAClC,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,QAAkB,EAAE,QAAQ,GAAG,QAAQ;IACjE,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;YAClC,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACpC,IAAI,GAAG;gBAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,IAAI,CAAC,SAAS,KAAK,MAAM,EAAE,CAAC;YACrC,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACpC,KAAK,CAAC,IAAI,CAAC,SAAS,QAAQ,KAAK,GAAG,UAAU,CAAC,CAAC;QAClD,CAAC;QACD,mDAAmD;IACrD,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;AACnC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Notebook } from "./notebook";
2
+ /**
3
+ * Serialize a `Notebook` to MyST Notebook Markdown.
4
+ *
5
+ * - Notebook metadata → YAML front matter (`---...---`)
6
+ * - Markdown cells → plain text separated by `+++` (with JSON metadata inline)
7
+ * - Code cells → ` ```{code-cell} ` directive with shorthand options
8
+ * - Raw cells → ` ```{raw-cell} ` directive with shorthand options
9
+ */
10
+ export declare function toMystMd(notebook: Notebook): string;
11
+ //# sourceMappingURL=toMystMd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toMystMd.d.ts","sourceRoot":"","sources":["../src/toMystMd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAgB3C;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CA+BnD"}
@@ -0,0 +1,51 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Notebook → MyST Markdown serializer
3
+ // ---------------------------------------------------------------------------
4
+ function joinSource(source) {
5
+ return source.join("");
6
+ }
7
+ function serializeOptions(meta) {
8
+ return Object.entries(meta).map(([key, val]) => typeof val === "string" ? `:${key}: ${val}` : `:${key}: ${JSON.stringify(val)}`);
9
+ }
10
+ /**
11
+ * Serialize a `Notebook` to MyST Notebook Markdown.
12
+ *
13
+ * - Notebook metadata → YAML front matter (`---...---`)
14
+ * - Markdown cells → plain text separated by `+++` (with JSON metadata inline)
15
+ * - Code cells → ` ```{code-cell} ` directive with shorthand options
16
+ * - Raw cells → ` ```{raw-cell} ` directive with shorthand options
17
+ */
18
+ export function toMystMd(notebook) {
19
+ const parts = [];
20
+ if (Object.keys(notebook.metadata).length > 0) {
21
+ const lines = Object.entries(notebook.metadata).map(([k, v]) => `${k}: ${v}`);
22
+ parts.push(`---\n${lines.join("\n")}\n---`);
23
+ }
24
+ for (const cell of notebook.cells) {
25
+ if (cell.cell_type === "markdown") {
26
+ const hasMeta = Object.keys(cell.metadata).length > 0;
27
+ if (parts.length > 0 || hasMeta) {
28
+ const metaStr = hasMeta ? ` ${JSON.stringify(cell.metadata)}` : "";
29
+ parts.push(`+++${metaStr}`);
30
+ }
31
+ const src = joinSource(cell.source);
32
+ if (src)
33
+ parts.push(src);
34
+ }
35
+ else {
36
+ const directive = cell.cell_type === "code" ? "code-cell" : "raw-cell";
37
+ const lines = [`\`\`\`{${directive}}`];
38
+ const optionLines = serializeOptions(cell.metadata);
39
+ lines.push(...optionLines);
40
+ if (optionLines.length > 0)
41
+ lines.push("");
42
+ const src = joinSource(cell.source);
43
+ if (src)
44
+ lines.push(src);
45
+ lines.push("```");
46
+ parts.push(lines.join("\n"));
47
+ }
48
+ }
49
+ return parts.join("\n\n") + "\n";
50
+ }
51
+ //# sourceMappingURL=toMystMd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toMystMd.js","sourceRoot":"","sources":["../src/toMystMd.ts"],"names":[],"mappings":"AAEA,8EAA8E;AAC9E,sCAAsC;AACtC,8EAA8E;AAE9E,SAAS,UAAU,CAAC,MAAgB;IAClC,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,gBAAgB,CAAC,IAA6B;IACrD,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAC7C,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAChF,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,QAAQ,CAAC,QAAkB;IACzC,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC9E,KAAK,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;YACtD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,EAAE,CAAC;gBAChC,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnE,KAAK,CAAC,IAAI,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC;YAC9B,CAAC;YACD,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACpC,IAAI,GAAG;gBAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC;YACvE,MAAM,KAAK,GAAa,CAAC,UAAU,SAAS,GAAG,CAAC,CAAC;YACjD,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACpD,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC;YAC3B,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC3C,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACpC,IAAI,GAAG;gBAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACzB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAClB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;AACnC,CAAC"}
package/dist/toPy.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import type { Notebook } from "./notebook";
2
+ /**
3
+ * Serialize a `Notebook` to the Python percent format (VS Code / Spyder / Jupytext).
4
+ *
5
+ * - Code cells → `# %%` delimiter + bare source
6
+ * - Markdown cells → `# %% [markdown]` delimiter + `# `-prefixed lines
7
+ * - Raw cells → `# %% [raw]` delimiter + `# `-prefixed lines
8
+ * - Cell name and tags from metadata are encoded in the delimiter line
9
+ */
10
+ export declare function toPy(notebook: Notebook): string;
11
+ //# sourceMappingURL=toPy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toPy.d.ts","sourceRoot":"","sources":["../src/toPy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AA6B3C;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAe/C"}
package/dist/toPy.js ADDED
@@ -0,0 +1,49 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Notebook → Python percent format serializer
3
+ // ---------------------------------------------------------------------------
4
+ function joinSource(source) {
5
+ return source.join("");
6
+ }
7
+ /** Prefix each line with `# ` (empty lines become bare `#`). */
8
+ function commentLines(text) {
9
+ return text
10
+ .split("\n")
11
+ .map((line) => (line === "" ? "#" : `# ${line}`))
12
+ .join("\n");
13
+ }
14
+ function buildDelimiter(cellType, meta) {
15
+ const parts = ["# %%"];
16
+ if (cellType === "markdown")
17
+ parts.push("[markdown]");
18
+ else if (cellType === "raw")
19
+ parts.push("[raw]");
20
+ if (typeof meta.name === "string" && meta.name)
21
+ parts.push(meta.name);
22
+ if (Array.isArray(meta.tags) && meta.tags.length > 0) {
23
+ parts.push(`tags='${JSON.stringify(meta.tags)}'`);
24
+ }
25
+ return parts.join(" ");
26
+ }
27
+ /**
28
+ * Serialize a `Notebook` to the Python percent format (VS Code / Spyder / Jupytext).
29
+ *
30
+ * - Code cells → `# %%` delimiter + bare source
31
+ * - Markdown cells → `# %% [markdown]` delimiter + `# `-prefixed lines
32
+ * - Raw cells → `# %% [raw]` delimiter + `# `-prefixed lines
33
+ * - Cell name and tags from metadata are encoded in the delimiter line
34
+ */
35
+ export function toPy(notebook) {
36
+ const parts = [];
37
+ for (const cell of notebook.cells) {
38
+ const delimiter = buildDelimiter(cell.cell_type, cell.metadata);
39
+ const src = joinSource(cell.source);
40
+ if (cell.cell_type === "code") {
41
+ parts.push(src ? `${delimiter}\n${src}` : delimiter);
42
+ }
43
+ else {
44
+ parts.push(src ? `${delimiter}\n${commentLines(src)}` : delimiter);
45
+ }
46
+ }
47
+ return parts.join("\n\n") + "\n";
48
+ }
49
+ //# sourceMappingURL=toPy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toPy.js","sourceRoot":"","sources":["../src/toPy.ts"],"names":[],"mappings":"AAEA,8EAA8E;AAC9E,8CAA8C;AAC9C,8EAA8E;AAE9E,SAAS,UAAU,CAAC,MAAgB;IAClC,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACzB,CAAC;AAED,gEAAgE;AAChE,SAAS,YAAY,CAAC,IAAY;IAChC,OAAO,IAAI;SACR,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;SAChD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,SAAS,cAAc,CAAC,QAAgB,EAAE,IAA6B;IACrE,MAAM,KAAK,GAAa,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,QAAQ,KAAK,UAAU;QAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;SACjD,IAAI,QAAQ,KAAK,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjD,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrD,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,IAAI,CAAC,QAAkB;IACrC,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChE,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEpC,IAAI,IAAI,CAAC,SAAS,KAAK,MAAM,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACvD,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,KAAK,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;AACnC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { Notebook } from "./notebook";
2
+ /**
3
+ * Serialize a `Notebook` to Sphinx Gallery Python script format.
4
+ *
5
+ * - First markdown cell → module-level triple-quoted docstring
6
+ * - Remaining markdown cells → `# %%` section with `# `-prefixed comment block
7
+ * - Code cells → `# %%` section with bare source
8
+ * - Adjacent [markdown, code] pairs are merged into a single `# %%` section
9
+ * (comment block above the code), matching how `parseSphinxGallery` splits them
10
+ * - Raw cells are omitted
11
+ */
12
+ export declare function toSphinxGallery(notebook: Notebook): string;
13
+ //# sourceMappingURL=toSphinxGallery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toSphinxGallery.d.ts","sourceRoot":"","sources":["../src/toSphinxGallery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAkB3C;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAsC1D"}
@@ -0,0 +1,60 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Notebook → Sphinx Gallery format serializer
3
+ // ---------------------------------------------------------------------------
4
+ function joinSource(source) {
5
+ return source.join("");
6
+ }
7
+ /** Prefix each line with `# ` (empty lines become bare `#`). */
8
+ function commentLines(text) {
9
+ return text
10
+ .split("\n")
11
+ .map((line) => (line === "" ? "#" : `# ${line}`))
12
+ .join("\n");
13
+ }
14
+ /**
15
+ * Serialize a `Notebook` to Sphinx Gallery Python script format.
16
+ *
17
+ * - First markdown cell → module-level triple-quoted docstring
18
+ * - Remaining markdown cells → `# %%` section with `# `-prefixed comment block
19
+ * - Code cells → `# %%` section with bare source
20
+ * - Adjacent [markdown, code] pairs are merged into a single `# %%` section
21
+ * (comment block above the code), matching how `parseSphinxGallery` splits them
22
+ * - Raw cells are omitted
23
+ */
24
+ export function toSphinxGallery(notebook) {
25
+ const parts = [];
26
+ const cells = notebook.cells.filter((c) => c.cell_type !== "raw");
27
+ let i = 0;
28
+ // First markdown cell → docstring
29
+ if (cells[0]?.cell_type === "markdown") {
30
+ const src = joinSource(cells[0].source);
31
+ parts.push(`"""\n${src}\n"""`);
32
+ i = 1;
33
+ }
34
+ while (i < cells.length) {
35
+ const cell = cells[i];
36
+ if (cell.cell_type === "markdown") {
37
+ const mdSrc = joinSource(cell.source);
38
+ const next = cells[i + 1];
39
+ if (next?.cell_type === "code") {
40
+ // Merge adjacent [markdown, code] into one section
41
+ const codeSrc = joinSource(next.source);
42
+ const section = `# %%\n${commentLines(mdSrc)}`;
43
+ parts.push(codeSrc ? `${section}\n\n${codeSrc}` : section);
44
+ i += 2;
45
+ }
46
+ else {
47
+ parts.push(`# %%\n${commentLines(mdSrc)}`);
48
+ i++;
49
+ }
50
+ }
51
+ else {
52
+ // code cell
53
+ const src = joinSource(cell.source);
54
+ parts.push(`# %%\n${src}`);
55
+ i++;
56
+ }
57
+ }
58
+ return parts.join("\n\n") + "\n";
59
+ }
60
+ //# sourceMappingURL=toSphinxGallery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toSphinxGallery.js","sourceRoot":"","sources":["../src/toSphinxGallery.ts"],"names":[],"mappings":"AAEA,8EAA8E;AAC9E,8CAA8C;AAC9C,8EAA8E;AAE9E,SAAS,UAAU,CAAC,MAAgB;IAClC,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACzB,CAAC;AAED,gEAAgE;AAChE,SAAS,YAAY,CAAC,IAAY;IAChC,OAAO,IAAI;SACR,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;SAChD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,QAAkB;IAChD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC;IAClE,IAAI,CAAC,GAAG,CAAC,CAAC;IAEV,kCAAkC;IAClC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,KAAK,UAAU,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACxC,KAAK,CAAC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,CAAC;QAC/B,CAAC,GAAG,CAAC,CAAC;IACR,CAAC;IAED,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAEtB,IAAI,IAAI,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAE1B,IAAI,IAAI,EAAE,SAAS,KAAK,MAAM,EAAE,CAAC;gBAC/B,mDAAmD;gBACnD,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACxC,MAAM,OAAO,GAAG,SAAS,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC/C,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,OAAO,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;gBAC3D,CAAC,IAAI,CAAC,CAAC;YACT,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,IAAI,CAAC,SAAS,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAC3C,CAAC,EAAE,CAAC;YACN,CAAC;QACH,CAAC;aAAM,CAAC;YACN,YAAY;YACZ,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACpC,KAAK,CAAC,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC;YAC3B,CAAC,EAAE,CAAC;QACN,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;AACnC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plainb",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Convert plain text (.py percent format, .md classic/MyST) to Jupyter nbformat 4 JSON",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -10,9 +10,9 @@
10
10
  ],
11
11
  "repository": {
12
12
  "type": "git",
13
- "url": "https://github.com/trungleduc/plainb"
13
+ "url": "https://github.com/notebook-link/plainb"
14
14
  },
15
- "homepage": "https://github.com/trungleduc/plainb",
15
+ "homepage": "https://github.com/notebook-link/plainb",
16
16
  "license": "MIT",
17
17
  "scripts": {
18
18
  "build": "tsc",