@tabnas/markdown 0.7.5 → 0.7.7

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
@@ -14,7 +14,7 @@ vendored GFM corpus, via `npm run conformance-gfm`.
14
14
  This is the canonical implementation; [`go/`](../go/README.md) is a port of it.
15
15
 
16
16
  [![npm version](https://img.shields.io/npm/v/@tabnas/markdown.svg)](https://npmjs.com/package/@tabnas/markdown)
17
- [![build](https://github.com/tabnas/markdown/actions/workflows/build.yml/badge.svg)](https://github.com/tabnas/markdown/actions/workflows/build.yml)
17
+ [![CI](https://github.com/tabnas/markdown/actions/workflows/ci.yml/badge.svg)](https://github.com/tabnas/markdown/actions/workflows/ci.yml)
18
18
 
19
19
  | ![Voxgig](https://www.voxgig.com/res/img/vgt01r.png) | This open source module is sponsored and supported by [Voxgig](https://www.voxgig.com). |
20
20
  | ---------------------------------------------------- | --------------------------------------------------------------------------------------- |
@@ -24,4 +24,6 @@ export type { DocumentNode, Block, HeadingNode, ParagraphNode, BlockquoteNode, L
24
24
  export { MdNode } from './node.ts';
25
25
  export type { ParserOptions } from './options.ts';
26
26
  export { renderHTML } from './html.ts';
27
- declare const VERSION = "0.7.5";
27
+ export { translate } from './translate';
28
+ export type { TranslationPart, TranslationParts } from './translate';
29
+ declare const VERSION = "0.7.7";
package/dist/markdown.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  /* Copyright (c) 2021-2026 Richard Rodger, MIT License */
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.renderHTML = exports.MdNode = exports.Markdown = exports.VERSION = void 0;
4
+ exports.translate = exports.renderHTML = exports.MdNode = exports.Markdown = exports.VERSION = void 0;
5
5
  exports.parseDocument = parseDocument;
6
6
  exports.parseInline = parseInline;
7
7
  exports.toHtml = toHtml;
@@ -156,9 +156,11 @@ Object.defineProperty(exports, "MdNode", { enumerable: true, get: function () {
156
156
  // and the two runtimes' public surfaces did not match.
157
157
  var html_ts_2 = require("./html.js");
158
158
  Object.defineProperty(exports, "renderHTML", { enumerable: true, get: function () { return html_ts_2.renderHTML; } });
159
+ var translate_1 = require("./translate");
160
+ Object.defineProperty(exports, "translate", { enumerable: true, get: function () { return translate_1.translate; } });
159
161
  // VERSION is this package's version. It MUST equal package.json "version":
160
162
  // the release orchestrator rewrites both, and the version test fails the
161
163
  // build if they drift. Mirrors `const VERSION` in go/markdown.go.
162
- const VERSION = '0.7.5';
164
+ const VERSION = '0.7.7';
163
165
  exports.VERSION = VERSION;
164
166
  //# sourceMappingURL=markdown.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ type TranslationPart = Readonly<{
2
+ entry: string;
3
+ source?: string;
4
+ }>;
5
+ type TranslationParts = Readonly<{
6
+ manifest: string;
7
+ lift?: TranslationPart;
8
+ render?: TranslationPart;
9
+ }>;
10
+ declare function translate(): TranslationParts | undefined;
11
+ export { translate, };
12
+ export type { TranslationPart, TranslationParts, };
@@ -0,0 +1,335 @@
1
+ "use strict";
2
+ /* Copyright (c) 2021-2026 Richard Rodger, MIT License */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.translate = translate;
5
+ const TRANSLATION = Object.freeze({
6
+ manifest: `{
7
+ "$schema": "https://tabnas.dev/schema/plugin.schema.json",
8
+ "name": "@tabnas/markdown",
9
+ "go": "github.com/tabnas/markdown/go",
10
+ "description": "CommonMark and GFM Markdown parsing for the tabnas engine.",
11
+ "engine": "@tabnas/parser",
12
+ "extensions": [
13
+ ".md",
14
+ ".markdown"
15
+ ],
16
+ "mediaTypes": [
17
+ "text/markdown"
18
+ ],
19
+ "languageId": "markdown",
20
+ "pluginKind": "grammar",
21
+ "specDir": "test/spec",
22
+ "clib": {
23
+ "dir": "go/clib",
24
+ "library": "libtabnasmarkdown",
25
+ "abi": "v1",
26
+ "errorCodes": [
27
+ "usage",
28
+ "grammar",
29
+ "handle",
30
+ "internal"
31
+ ]
32
+ },
33
+ "errorCodes": [],
34
+ "docs": "https://tabnas.dev/docs/packages",
35
+ "repository": "https://github.com/tabnas/markdown",
36
+ "versionSource": "ts/package.json",
37
+ "translate": {
38
+ "reads": [
39
+ "records",
40
+ "tree"
41
+ ],
42
+ "writes": "records",
43
+ "lift": "alchemy/lift.alc",
44
+ "render": "alchemy/render.alc",
45
+ "loss": [
46
+ "Only a document holding one table is read as records: a document with no table, or with more than one, is refused.",
47
+ "Inline markup in a cell is flattened to its text when it is read, an image to its alt text, and a written cell is plain text, so text that spells inline markup reads back as that markup.",
48
+ "Column alignment is not kept.",
49
+ "A line break in a cell is written as a space.",
50
+ "Leading and trailing spaces in a cell are not kept.",
51
+ "A U+0000 in a cell is written as it is, and the reader replaces it with U+FFFD when the table is read back."
52
+ ]
53
+ }
54
+ }
55
+ `,
56
+ lift: Object.freeze({ entry: "markdown-lift", source: `; Markdown's lift: a document's events, as the reader builds them, read
57
+ ; as a table's records: the TableRows protocol the standard library's
58
+ ; \`table-from-json\` answers, one \`schema\`, a \`row\` per record and
59
+ ; \`table-end\`. This is a library of definitions, each named
60
+ ; \`markdown-...\`, which a host links with its own program (alchemy's
61
+ ; \`compile_sources\`); its entry point is \`markdown-lift\`, and nothing
62
+ ; else here is the host's to call.
63
+ ;
64
+ ; The reader's tree is mdast's shape: a \`document\` whose \`children\` are
65
+ ; blocks, a \`table\` among them whose \`children\` are \`tableRow\`s of
66
+ ; \`tableCell\`s, and each cell's \`children\` the inline nodes of its text:
67
+ ; \`text\`, \`inlineCode\` and \`html\` with a \`value\`, \`image\` with an \`alt\`,
68
+ ; and \`emphasis\`, \`strong\`, \`link\` and the rest with \`children\` of their
69
+ ; own. \`type\` is each node's first member. The lift takes the first
70
+ ; row's cells as the column labels and every later row as a record, and
71
+ ; reads nothing else of the document: not the blocks around the table,
72
+ ; and not the table's \`align\`. A cell is the text under it, every
73
+ ; \`value\` and every image's \`alt\` in order, joined into one string
74
+ ; (\`string-join\`, which alchemy has for this lift: \`concat\` and \`join\`
75
+ ; answer a text, which a cell may not be), so inline markup is
76
+ ; flattened to its text and an image to its alt text, and every cell is
77
+ ; a string, as the CSV reader's records are: an empty cell is "", and a
78
+ ; cell of text beside emphasis, a link, an image, inline HTML or an
79
+ ; autolink is their texts run together, \`Bob *b*\` as \`Bob b\`.
80
+ ;
81
+ ; The document must hold exactly one table: a second table, or none by
82
+ ; the end, is a failure (INPUT_INVALID) that says so, since a Markdown
83
+ ; document is read as records through its table and nothing else.
84
+ ;
85
+ ; The state is one vector, [stack phase seen in-cell runs cells]:
86
+ ; stack the open containers, one marker each: \`:array\`, \`:node\` for
87
+ ; an object whose type is not known yet or is any other node,
88
+ ; and \`:table\`, \`:row\` or \`:cell\` once its \`type\` has named
89
+ ; one, so that its end is known when its object ends;
90
+ ; phase \`:before\` the table, \`:header\` inside it until its first
91
+ ; row ends, \`:body\` once the schema is written, \`:after\` it;
92
+ ; seen what the last key was, \`:type\`, \`:text\` (a \`value\` or an
93
+ ; \`alt\`) or \`:other\`, so that the scalar after it is classified;
94
+ ; in-cell whether a cell is open, so that text under it is the cell's;
95
+ ; runs the open cell's runs of text, in order;
96
+ ; cells the open row's cells, as wide as one row.
97
+ ; It grows with the document's nesting and with one row's width, never
98
+ ; with the table's length: a row is emitted when its object ends and
99
+ ; dropped. Events no tree has (a key outside an object, an end with
100
+ ; nothing open) fail with INPUT_INVALID, saying so.
101
+
102
+ ; A column record of the TableRows protocol, as the standard library's
103
+ ; \`public-column\` makes one.
104
+ def markdown-column [label]
105
+ record
106
+ entry :label label
107
+
108
+ ; A cell's text: its runs, in order, as one string.
109
+ def markdown-cell-text [runs]
110
+ string-join "" runs
111
+
112
+ ; A \`value\` or an image's \`alt\` under a cell, which the reader's tree
113
+ ; makes a string.
114
+ def markdown-run [value]
115
+ match (kind value)
116
+ case :string value
117
+ case _ (fail "a node's value or alt under a table cell is not a string, which the reader's tree never has")
118
+
119
+ ; What the scalar after a key is: the one after \`type\` names the node,
120
+ ; the one after \`value\` (a text, code or HTML node's text) or \`alt\` (an
121
+ ; image's alt text) is a run of text, any other is neither.
122
+ def markdown-seen [name]
123
+ match name
124
+ case "type" :type
125
+ case "value" :text
126
+ case "alt" :text
127
+ case _ :other
128
+
129
+ ; The top marker, or \`:none\` with nothing open.
130
+ def markdown-top [stack]
131
+ match (count stack)
132
+ case 0 :none
133
+ case _ (top stack)
134
+
135
+ ; The open object's marker, once its \`type\` has named it.
136
+ def markdown-mark [marker stack]
137
+ push marker (pop stack)
138
+
139
+ ; The scalar after \`type\`: the three nodes the lift reads leave their
140
+ ; marker on the stack and move the phase; any other node is \`:node\`.
141
+ def markdown-node [name stack phase in-cell runs cells]
142
+ match name
143
+ case "table"
144
+ match phase
145
+ case :before (transition [(markdown-mark :table stack) :header :other in-cell runs cells] [])
146
+ case :after (fail "the document holds a second table, and only a document of one table is read as records")
147
+ case _ (fail "the events hold a table inside a table, which the reader's tree never has")
148
+ case "tableRow"
149
+ match phase
150
+ case :before (fail "the events hold a table row outside a table, which the reader's tree never has")
151
+ case :after (fail "the events hold a table row outside a table, which the reader's tree never has")
152
+ case _ (transition [(markdown-mark :row stack) phase :other in-cell runs []] [])
153
+ case "tableCell"
154
+ match phase
155
+ case :before (fail "the events hold a table cell outside a table, which the reader's tree never has")
156
+ case :after (fail "the events hold a table cell outside a table, which the reader's tree never has")
157
+ case _
158
+ if in-cell
159
+ fail "the events hold a table cell inside a cell, which the reader's tree never has"
160
+ transition [(markdown-mark :cell stack) phase :other true [] cells] []
161
+ case _ (transition [stack phase :other in-cell runs cells] [])
162
+
163
+ ; An object's end: a cell joins its row, a row is the schema or a
164
+ ; record, the table is done, and any other node is dropped.
165
+ def markdown-close [stack phase in-cell runs cells]
166
+ match (markdown-top stack)
167
+ case :cell
168
+ transition [(pop stack) phase :other false [] (push (markdown-cell-text runs) cells)] []
169
+ case :row
170
+ match phase
171
+ case :header
172
+ transition [(pop stack) :body :other in-cell runs []] [(schema (map markdown-column cells))]
173
+ case _
174
+ transition [(pop stack) phase :other in-cell runs []] [(row cells)]
175
+ case :table
176
+ transition [(pop stack) :after :other in-cell runs cells] []
177
+ case :node
178
+ transition [(pop stack) phase :other in-cell runs cells] []
179
+ case _ (fail "the events end an object that is not open, which a tree's never do")
180
+
181
+ def markdown-event [stack phase seen in-cell runs cells event]
182
+ match event
183
+ case object-start
184
+ transition [(push :node stack) phase :other in-cell runs cells] []
185
+ case array-start
186
+ transition [(push :array stack) phase :other in-cell runs cells] []
187
+ case (key name)
188
+ match (markdown-top stack)
189
+ case :none (fail "the events hold a key outside an object, which a tree's never do")
190
+ case :array (fail "the events hold a key inside an array, which a tree's never do")
191
+ case _ (transition [stack phase (markdown-seen name) in-cell runs cells] [])
192
+ case (scalar value)
193
+ match seen
194
+ case :type (markdown-node value stack phase in-cell runs cells)
195
+ case :text
196
+ if in-cell
197
+ transition [stack phase :other in-cell (push (markdown-run value) runs) cells] []
198
+ transition [stack phase :other in-cell runs cells] []
199
+ case _ (transition [stack phase :other in-cell runs cells] [])
200
+ case object-end (markdown-close stack phase in-cell runs cells)
201
+ case array-end
202
+ match (markdown-top stack)
203
+ case :array (transition [(pop stack) phase :other in-cell runs cells] [])
204
+ case _ (fail "the events end an array that is not open, which a tree's never do")
205
+
206
+ def markdown-lift-step [s event]
207
+ match s
208
+ case [stack phase seen in-cell runs cells]
209
+ markdown-event stack phase seen in-cell runs cells event
210
+
211
+ def markdown-lift-finish [s]
212
+ match s
213
+ case [stack phase seen in-cell runs cells]
214
+ match phase
215
+ case :after
216
+ match (count stack)
217
+ case 0 [table-end]
218
+ case _ (fail "the events ended inside a container, which a tree's never do")
219
+ case :before (fail "the document holds no table, and only a document of one table is read as records")
220
+ case _ (fail "the events ended inside the table, which a tree's never do")
221
+
222
+ ; The lift: the document's events in, the table's records out.
223
+ def markdown-lift [input]
224
+ scan-emit [[] :before :other false [] []] markdown-lift-step markdown-lift-finish (events input)
225
+ ` }),
226
+ render: Object.freeze({ entry: "markdown-render", source: `; Markdown's render: a table's records, the TableRows protocol (one
227
+ ; \`schema\`, a \`row\` per record and \`table-end\`), written as one GFM pipe
228
+ ; table. This is a library of definitions, each named \`markdown-...\`,
229
+ ; which a host links with its own program (alchemy's \`compile_sources\`);
230
+ ; its entry point is \`markdown-render\`, and nothing else here is the
231
+ ; host's to call.
232
+ ;
233
+ ; The table is the header row, \`| Name | Age |\`, the delimiter row,
234
+ ; \`| --- | --- |\`, and a row per record, each line ended by a line feed
235
+ ; and every cell between \`| \` and \` |\`. A cell is its value's text as
236
+ ; the CSV renderer writes it (\`scalar-text\`: a string as it is, a number
237
+ ; by its lexeme, a boolean by its name, null and a missing cell as
238
+ ; nothing, a vector or a record as its compact JSON text), with every
239
+ ; backslash doubled and every pipe escaped as \`\\|\`, which the reader
240
+ ; turns back into the characters (the reader's split skips the byte
241
+ ; after a backslash, so the pipe's escape holds only when a backslash
242
+ ; before it is itself escaped), and every line break replaced by a
243
+ ; space, since a row is one line. No other character is escaped: the
244
+ ; render cannot look at one (alchemy has no character test), so a cell
245
+ ; is plain text, and text that spells inline markup reads back as that
246
+ ; markup. A U+0000 in a cell is written as it is for the same reason,
247
+ ; and the reader replaces it with U+FFFD, as CommonMark asks of every
248
+ ; reader; the loss declaration says so. Alignment is not written: every
249
+ ; column's delimiter is \`---\`.
250
+ ;
251
+ ; The state is one marker: \`:start\` before the schema, the schema's
252
+ ; width (a number) while rows may follow, and \`:ended\` after
253
+ ; \`table-end\`, so that a stream which breaks the protocol (a row before
254
+ ; the schema, a second schema, a row of another width, anything after
255
+ ; the end, no end) fails with INPUT_INVALID, saying so, rather than
256
+ ; being written. The check is this file's rather than \`csv-table\`'s,
257
+ ; whose refusals speak of CSV. A schema of no columns fails too: a row
258
+ ; needs at least one cell, so such a table has no Markdown form.
259
+
260
+ ; What \`scalar-text\` reads: null and a missing cell are written as
261
+ ; nothing, where the CSV renderer's \`csv-options\` map a missing cell to
262
+ ; an error.
263
+ def markdown-options
264
+ record
265
+ entry :null-text ""
266
+ entry :missing ""
267
+
268
+ ; A cell's text, as it stands between the pipes.
269
+ def markdown-cell [cell]
270
+ replace-text "\\r" " "
271
+ replace-text "\\n" " "
272
+ replace-text "\\r\\n" " "
273
+ replace-text "|" "\\\\|"
274
+ replace-text "\\\\" "\\\\\\\\"
275
+ scalar-text markdown-options cell
276
+
277
+ def markdown-label [column]
278
+ markdown-cell (get :label column)
279
+
280
+ ; One row of the table, cells in order.
281
+ def markdown-line [cells]
282
+ concat
283
+ "| "
284
+ join " | " cells
285
+ " |\\n"
286
+
287
+ ; The delimiter row under the header, one \`---\` per column.
288
+ def markdown-delimiter [width]
289
+ concat
290
+ repeat width "| --- "
291
+ "|\\n"
292
+
293
+ def markdown-render-step [s event]
294
+ match event
295
+ case (schema columns)
296
+ match s
297
+ case :start
298
+ match (count columns)
299
+ case 0 (fail "a table of no columns has no Markdown form: a row needs at least one cell")
300
+ case _
301
+ transition (count columns)
302
+ vector
303
+ markdown-line (map markdown-label columns)
304
+ markdown-delimiter (count columns)
305
+ case _ (fail "the events hold a second schema, where a table's hold one")
306
+ case (row cells)
307
+ match s
308
+ case :start (fail "the events hold a row before the schema, which a table's never do")
309
+ case :ended (fail "the events hold a row after table-end, which a table's never do")
310
+ case _
311
+ match (compare (count cells) s)
312
+ case :equal (transition s [(markdown-line (map markdown-cell cells))])
313
+ case _ (fail "the events hold a row that is not as wide as the schema, which a table's never do")
314
+ case table-end
315
+ match s
316
+ case :start (fail "the events end before the schema, which a table's never do")
317
+ case :ended (fail "the events hold a second table-end, which a table's never do")
318
+ case _ (transition :ended [])
319
+
320
+ def markdown-render-finish [s]
321
+ match s
322
+ case :ended []
323
+ case :start (fail "the events hold no schema, where a table's hold one first")
324
+ case _ (fail "the events ended before table-end, which a table's never do")
325
+
326
+ ; The render: the table's records in, the pipe table's text out.
327
+ def markdown-render [input]
328
+ join ""
329
+ scan-emit :start markdown-render-step markdown-render-finish input
330
+ ` })
331
+ });
332
+ function translate() {
333
+ return TRANSLATION;
334
+ }
335
+ //# sourceMappingURL=translate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translate.js","sourceRoot":"","sources":["../src/translate.ts"],"names":[],"mappings":";AAAA,yDAAyD;;QA6VvD,SAAS;AA7UX,MAAM,WAAW,GAAqB,MAAM,CAAC,MAAM,CAAC;IAClD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiDX;IACC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyKvD,EAAE,CAAC;IACF,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwG3D,EAAE,CAAC;CACH,CAAC,CAAA;AAEF,SAAS,SAAS;IAChB,OAAO,WAAW,CAAA;AACpB,CAAC"}
@@ -1 +1 @@
1
- {"version":"7.0.2","root":["../src/ast.ts","../src/block.ts","../src/common.ts","../src/commonmark.ts","../src/engine-block.ts","../src/engine-inline.ts","../src/entities.ts","../src/html.ts","../src/inline.ts","../src/markdown.ts","../src/node.ts","../src/options.ts"],"packageJsons":["../node_modules/@tabnas/parser/package.json","../package.json"],"missingPackageJsons":["../node_modules/@tabnas/parser/dist/package.json"]}
1
+ {"version":"7.0.2","root":["../src/ast.ts","../src/block.ts","../src/common.ts","../src/commonmark.ts","../src/engine-block.ts","../src/engine-inline.ts","../src/entities.ts","../src/html.ts","../src/inline.ts","../src/markdown.ts","../src/node.ts","../src/options.ts","../src/translate.ts"],"packageJsons":["../node_modules/@tabnas/parser/package.json","../package.json"],"missingPackageJsons":["../node_modules/@tabnas/parser/dist/package.json"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tabnas/markdown",
3
- "version": "0.7.5",
4
- "description": "A Tabnas parser plugin for CommonMark/GFM Markdown \u2014 headings, lists, blockquotes, code, emphasis, links and more, into a JSON AST.",
3
+ "version": "0.7.7",
4
+ "description": "A Tabnas parser plugin for CommonMark/GFM Markdown — headings, lists, blockquotes, code, emphasis, links and more, into a JSON AST.",
5
5
  "main": "dist/markdown.js",
6
6
  "type": "commonjs",
7
7
  "types": "dist/markdown.d.ts",
@@ -30,7 +30,8 @@
30
30
  "pretest-watch": "npm run build",
31
31
  "test-watch": "node --test --watch dist-test/markdown.test.js",
32
32
  "watch": "tsc --build src test -w",
33
- "build": "tsc --build src && tsc --build test",
33
+ "embed": "node embed-translate.js",
34
+ "build": "npm run embed && tsc --build src && tsc --build test",
34
35
  "clean": "rm -rf node_modules dist dist-test yarn.lock package-lock.json",
35
36
  "reset": "npm run clean && npm i && npm run build && npm test",
36
37
  "repo-tag": "REPO_VERSION=`node -e \"console.log(require('./package').version)\"` && echo TAG: ts/v$REPO_VERSION && git commit -a -m v$REPO_VERSION && git push && git tag ts/v$REPO_VERSION && git push origin ts/v$REPO_VERSION;",
package/src/markdown.ts CHANGED
@@ -230,7 +230,10 @@ export type { ParserOptions } from './options.ts'
230
230
  // and the two runtimes' public surfaces did not match.
231
231
  export { renderHTML } from './html.ts'
232
232
 
233
+ export { translate } from './translate'
234
+ export type { TranslationPart, TranslationParts } from './translate'
235
+
233
236
  // VERSION is this package's version. It MUST equal package.json "version":
234
237
  // the release orchestrator rewrites both, and the version test fails the
235
238
  // build if they drift. Mirrors `const VERSION` in go/markdown.go.
236
- const VERSION = '0.7.5'
239
+ const VERSION = '0.7.7'
@@ -0,0 +1,356 @@
1
+ /* Copyright (c) 2021-2026 Richard Rodger, MIT License */
2
+
3
+ // Generated by ../embed-translate.js. Edit tabnas.plugin.json or alchemy/*,
4
+ // then run npm run embed.
5
+
6
+ type TranslationPart = Readonly<{
7
+ entry: string
8
+ source?: string
9
+ }>
10
+
11
+ type TranslationParts = Readonly<{
12
+ manifest: string
13
+ lift?: TranslationPart
14
+ render?: TranslationPart
15
+ }>
16
+
17
+ const TRANSLATION: TranslationParts = Object.freeze({
18
+ manifest: `{
19
+ "$schema": "https://tabnas.dev/schema/plugin.schema.json",
20
+ "name": "@tabnas/markdown",
21
+ "go": "github.com/tabnas/markdown/go",
22
+ "description": "CommonMark and GFM Markdown parsing for the tabnas engine.",
23
+ "engine": "@tabnas/parser",
24
+ "extensions": [
25
+ ".md",
26
+ ".markdown"
27
+ ],
28
+ "mediaTypes": [
29
+ "text/markdown"
30
+ ],
31
+ "languageId": "markdown",
32
+ "pluginKind": "grammar",
33
+ "specDir": "test/spec",
34
+ "clib": {
35
+ "dir": "go/clib",
36
+ "library": "libtabnasmarkdown",
37
+ "abi": "v1",
38
+ "errorCodes": [
39
+ "usage",
40
+ "grammar",
41
+ "handle",
42
+ "internal"
43
+ ]
44
+ },
45
+ "errorCodes": [],
46
+ "docs": "https://tabnas.dev/docs/packages",
47
+ "repository": "https://github.com/tabnas/markdown",
48
+ "versionSource": "ts/package.json",
49
+ "translate": {
50
+ "reads": [
51
+ "records",
52
+ "tree"
53
+ ],
54
+ "writes": "records",
55
+ "lift": "alchemy/lift.alc",
56
+ "render": "alchemy/render.alc",
57
+ "loss": [
58
+ "Only a document holding one table is read as records: a document with no table, or with more than one, is refused.",
59
+ "Inline markup in a cell is flattened to its text when it is read, an image to its alt text, and a written cell is plain text, so text that spells inline markup reads back as that markup.",
60
+ "Column alignment is not kept.",
61
+ "A line break in a cell is written as a space.",
62
+ "Leading and trailing spaces in a cell are not kept.",
63
+ "A U+0000 in a cell is written as it is, and the reader replaces it with U+FFFD when the table is read back."
64
+ ]
65
+ }
66
+ }
67
+ `,
68
+ lift: Object.freeze({ entry: "markdown-lift", source: `; Markdown's lift: a document's events, as the reader builds them, read
69
+ ; as a table's records: the TableRows protocol the standard library's
70
+ ; \`table-from-json\` answers, one \`schema\`, a \`row\` per record and
71
+ ; \`table-end\`. This is a library of definitions, each named
72
+ ; \`markdown-...\`, which a host links with its own program (alchemy's
73
+ ; \`compile_sources\`); its entry point is \`markdown-lift\`, and nothing
74
+ ; else here is the host's to call.
75
+ ;
76
+ ; The reader's tree is mdast's shape: a \`document\` whose \`children\` are
77
+ ; blocks, a \`table\` among them whose \`children\` are \`tableRow\`s of
78
+ ; \`tableCell\`s, and each cell's \`children\` the inline nodes of its text:
79
+ ; \`text\`, \`inlineCode\` and \`html\` with a \`value\`, \`image\` with an \`alt\`,
80
+ ; and \`emphasis\`, \`strong\`, \`link\` and the rest with \`children\` of their
81
+ ; own. \`type\` is each node's first member. The lift takes the first
82
+ ; row's cells as the column labels and every later row as a record, and
83
+ ; reads nothing else of the document: not the blocks around the table,
84
+ ; and not the table's \`align\`. A cell is the text under it, every
85
+ ; \`value\` and every image's \`alt\` in order, joined into one string
86
+ ; (\`string-join\`, which alchemy has for this lift: \`concat\` and \`join\`
87
+ ; answer a text, which a cell may not be), so inline markup is
88
+ ; flattened to its text and an image to its alt text, and every cell is
89
+ ; a string, as the CSV reader's records are: an empty cell is "", and a
90
+ ; cell of text beside emphasis, a link, an image, inline HTML or an
91
+ ; autolink is their texts run together, \`Bob *b*\` as \`Bob b\`.
92
+ ;
93
+ ; The document must hold exactly one table: a second table, or none by
94
+ ; the end, is a failure (INPUT_INVALID) that says so, since a Markdown
95
+ ; document is read as records through its table and nothing else.
96
+ ;
97
+ ; The state is one vector, [stack phase seen in-cell runs cells]:
98
+ ; stack the open containers, one marker each: \`:array\`, \`:node\` for
99
+ ; an object whose type is not known yet or is any other node,
100
+ ; and \`:table\`, \`:row\` or \`:cell\` once its \`type\` has named
101
+ ; one, so that its end is known when its object ends;
102
+ ; phase \`:before\` the table, \`:header\` inside it until its first
103
+ ; row ends, \`:body\` once the schema is written, \`:after\` it;
104
+ ; seen what the last key was, \`:type\`, \`:text\` (a \`value\` or an
105
+ ; \`alt\`) or \`:other\`, so that the scalar after it is classified;
106
+ ; in-cell whether a cell is open, so that text under it is the cell's;
107
+ ; runs the open cell's runs of text, in order;
108
+ ; cells the open row's cells, as wide as one row.
109
+ ; It grows with the document's nesting and with one row's width, never
110
+ ; with the table's length: a row is emitted when its object ends and
111
+ ; dropped. Events no tree has (a key outside an object, an end with
112
+ ; nothing open) fail with INPUT_INVALID, saying so.
113
+
114
+ ; A column record of the TableRows protocol, as the standard library's
115
+ ; \`public-column\` makes one.
116
+ def markdown-column [label]
117
+ record
118
+ entry :label label
119
+
120
+ ; A cell's text: its runs, in order, as one string.
121
+ def markdown-cell-text [runs]
122
+ string-join "" runs
123
+
124
+ ; A \`value\` or an image's \`alt\` under a cell, which the reader's tree
125
+ ; makes a string.
126
+ def markdown-run [value]
127
+ match (kind value)
128
+ case :string value
129
+ case _ (fail "a node's value or alt under a table cell is not a string, which the reader's tree never has")
130
+
131
+ ; What the scalar after a key is: the one after \`type\` names the node,
132
+ ; the one after \`value\` (a text, code or HTML node's text) or \`alt\` (an
133
+ ; image's alt text) is a run of text, any other is neither.
134
+ def markdown-seen [name]
135
+ match name
136
+ case "type" :type
137
+ case "value" :text
138
+ case "alt" :text
139
+ case _ :other
140
+
141
+ ; The top marker, or \`:none\` with nothing open.
142
+ def markdown-top [stack]
143
+ match (count stack)
144
+ case 0 :none
145
+ case _ (top stack)
146
+
147
+ ; The open object's marker, once its \`type\` has named it.
148
+ def markdown-mark [marker stack]
149
+ push marker (pop stack)
150
+
151
+ ; The scalar after \`type\`: the three nodes the lift reads leave their
152
+ ; marker on the stack and move the phase; any other node is \`:node\`.
153
+ def markdown-node [name stack phase in-cell runs cells]
154
+ match name
155
+ case "table"
156
+ match phase
157
+ case :before (transition [(markdown-mark :table stack) :header :other in-cell runs cells] [])
158
+ case :after (fail "the document holds a second table, and only a document of one table is read as records")
159
+ case _ (fail "the events hold a table inside a table, which the reader's tree never has")
160
+ case "tableRow"
161
+ match phase
162
+ case :before (fail "the events hold a table row outside a table, which the reader's tree never has")
163
+ case :after (fail "the events hold a table row outside a table, which the reader's tree never has")
164
+ case _ (transition [(markdown-mark :row stack) phase :other in-cell runs []] [])
165
+ case "tableCell"
166
+ match phase
167
+ case :before (fail "the events hold a table cell outside a table, which the reader's tree never has")
168
+ case :after (fail "the events hold a table cell outside a table, which the reader's tree never has")
169
+ case _
170
+ if in-cell
171
+ fail "the events hold a table cell inside a cell, which the reader's tree never has"
172
+ transition [(markdown-mark :cell stack) phase :other true [] cells] []
173
+ case _ (transition [stack phase :other in-cell runs cells] [])
174
+
175
+ ; An object's end: a cell joins its row, a row is the schema or a
176
+ ; record, the table is done, and any other node is dropped.
177
+ def markdown-close [stack phase in-cell runs cells]
178
+ match (markdown-top stack)
179
+ case :cell
180
+ transition [(pop stack) phase :other false [] (push (markdown-cell-text runs) cells)] []
181
+ case :row
182
+ match phase
183
+ case :header
184
+ transition [(pop stack) :body :other in-cell runs []] [(schema (map markdown-column cells))]
185
+ case _
186
+ transition [(pop stack) phase :other in-cell runs []] [(row cells)]
187
+ case :table
188
+ transition [(pop stack) :after :other in-cell runs cells] []
189
+ case :node
190
+ transition [(pop stack) phase :other in-cell runs cells] []
191
+ case _ (fail "the events end an object that is not open, which a tree's never do")
192
+
193
+ def markdown-event [stack phase seen in-cell runs cells event]
194
+ match event
195
+ case object-start
196
+ transition [(push :node stack) phase :other in-cell runs cells] []
197
+ case array-start
198
+ transition [(push :array stack) phase :other in-cell runs cells] []
199
+ case (key name)
200
+ match (markdown-top stack)
201
+ case :none (fail "the events hold a key outside an object, which a tree's never do")
202
+ case :array (fail "the events hold a key inside an array, which a tree's never do")
203
+ case _ (transition [stack phase (markdown-seen name) in-cell runs cells] [])
204
+ case (scalar value)
205
+ match seen
206
+ case :type (markdown-node value stack phase in-cell runs cells)
207
+ case :text
208
+ if in-cell
209
+ transition [stack phase :other in-cell (push (markdown-run value) runs) cells] []
210
+ transition [stack phase :other in-cell runs cells] []
211
+ case _ (transition [stack phase :other in-cell runs cells] [])
212
+ case object-end (markdown-close stack phase in-cell runs cells)
213
+ case array-end
214
+ match (markdown-top stack)
215
+ case :array (transition [(pop stack) phase :other in-cell runs cells] [])
216
+ case _ (fail "the events end an array that is not open, which a tree's never do")
217
+
218
+ def markdown-lift-step [s event]
219
+ match s
220
+ case [stack phase seen in-cell runs cells]
221
+ markdown-event stack phase seen in-cell runs cells event
222
+
223
+ def markdown-lift-finish [s]
224
+ match s
225
+ case [stack phase seen in-cell runs cells]
226
+ match phase
227
+ case :after
228
+ match (count stack)
229
+ case 0 [table-end]
230
+ case _ (fail "the events ended inside a container, which a tree's never do")
231
+ case :before (fail "the document holds no table, and only a document of one table is read as records")
232
+ case _ (fail "the events ended inside the table, which a tree's never do")
233
+
234
+ ; The lift: the document's events in, the table's records out.
235
+ def markdown-lift [input]
236
+ scan-emit [[] :before :other false [] []] markdown-lift-step markdown-lift-finish (events input)
237
+ ` }),
238
+ render: Object.freeze({ entry: "markdown-render", source: `; Markdown's render: a table's records, the TableRows protocol (one
239
+ ; \`schema\`, a \`row\` per record and \`table-end\`), written as one GFM pipe
240
+ ; table. This is a library of definitions, each named \`markdown-...\`,
241
+ ; which a host links with its own program (alchemy's \`compile_sources\`);
242
+ ; its entry point is \`markdown-render\`, and nothing else here is the
243
+ ; host's to call.
244
+ ;
245
+ ; The table is the header row, \`| Name | Age |\`, the delimiter row,
246
+ ; \`| --- | --- |\`, and a row per record, each line ended by a line feed
247
+ ; and every cell between \`| \` and \` |\`. A cell is its value's text as
248
+ ; the CSV renderer writes it (\`scalar-text\`: a string as it is, a number
249
+ ; by its lexeme, a boolean by its name, null and a missing cell as
250
+ ; nothing, a vector or a record as its compact JSON text), with every
251
+ ; backslash doubled and every pipe escaped as \`\\|\`, which the reader
252
+ ; turns back into the characters (the reader's split skips the byte
253
+ ; after a backslash, so the pipe's escape holds only when a backslash
254
+ ; before it is itself escaped), and every line break replaced by a
255
+ ; space, since a row is one line. No other character is escaped: the
256
+ ; render cannot look at one (alchemy has no character test), so a cell
257
+ ; is plain text, and text that spells inline markup reads back as that
258
+ ; markup. A U+0000 in a cell is written as it is for the same reason,
259
+ ; and the reader replaces it with U+FFFD, as CommonMark asks of every
260
+ ; reader; the loss declaration says so. Alignment is not written: every
261
+ ; column's delimiter is \`---\`.
262
+ ;
263
+ ; The state is one marker: \`:start\` before the schema, the schema's
264
+ ; width (a number) while rows may follow, and \`:ended\` after
265
+ ; \`table-end\`, so that a stream which breaks the protocol (a row before
266
+ ; the schema, a second schema, a row of another width, anything after
267
+ ; the end, no end) fails with INPUT_INVALID, saying so, rather than
268
+ ; being written. The check is this file's rather than \`csv-table\`'s,
269
+ ; whose refusals speak of CSV. A schema of no columns fails too: a row
270
+ ; needs at least one cell, so such a table has no Markdown form.
271
+
272
+ ; What \`scalar-text\` reads: null and a missing cell are written as
273
+ ; nothing, where the CSV renderer's \`csv-options\` map a missing cell to
274
+ ; an error.
275
+ def markdown-options
276
+ record
277
+ entry :null-text ""
278
+ entry :missing ""
279
+
280
+ ; A cell's text, as it stands between the pipes.
281
+ def markdown-cell [cell]
282
+ replace-text "\\r" " "
283
+ replace-text "\\n" " "
284
+ replace-text "\\r\\n" " "
285
+ replace-text "|" "\\\\|"
286
+ replace-text "\\\\" "\\\\\\\\"
287
+ scalar-text markdown-options cell
288
+
289
+ def markdown-label [column]
290
+ markdown-cell (get :label column)
291
+
292
+ ; One row of the table, cells in order.
293
+ def markdown-line [cells]
294
+ concat
295
+ "| "
296
+ join " | " cells
297
+ " |\\n"
298
+
299
+ ; The delimiter row under the header, one \`---\` per column.
300
+ def markdown-delimiter [width]
301
+ concat
302
+ repeat width "| --- "
303
+ "|\\n"
304
+
305
+ def markdown-render-step [s event]
306
+ match event
307
+ case (schema columns)
308
+ match s
309
+ case :start
310
+ match (count columns)
311
+ case 0 (fail "a table of no columns has no Markdown form: a row needs at least one cell")
312
+ case _
313
+ transition (count columns)
314
+ vector
315
+ markdown-line (map markdown-label columns)
316
+ markdown-delimiter (count columns)
317
+ case _ (fail "the events hold a second schema, where a table's hold one")
318
+ case (row cells)
319
+ match s
320
+ case :start (fail "the events hold a row before the schema, which a table's never do")
321
+ case :ended (fail "the events hold a row after table-end, which a table's never do")
322
+ case _
323
+ match (compare (count cells) s)
324
+ case :equal (transition s [(markdown-line (map markdown-cell cells))])
325
+ case _ (fail "the events hold a row that is not as wide as the schema, which a table's never do")
326
+ case table-end
327
+ match s
328
+ case :start (fail "the events end before the schema, which a table's never do")
329
+ case :ended (fail "the events hold a second table-end, which a table's never do")
330
+ case _ (transition :ended [])
331
+
332
+ def markdown-render-finish [s]
333
+ match s
334
+ case :ended []
335
+ case :start (fail "the events hold no schema, where a table's hold one first")
336
+ case _ (fail "the events ended before table-end, which a table's never do")
337
+
338
+ ; The render: the table's records in, the pipe table's text out.
339
+ def markdown-render [input]
340
+ join ""
341
+ scan-emit :start markdown-render-step markdown-render-finish input
342
+ ` })
343
+ })
344
+
345
+ function translate (): TranslationParts | undefined {
346
+ return TRANSLATION
347
+ }
348
+
349
+ export {
350
+ translate,
351
+ }
352
+
353
+ export type {
354
+ TranslationPart,
355
+ TranslationParts,
356
+ }