@jianwen-lang/parser 0.1.1 → 0.1.2

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.
Files changed (34) hide show
  1. package/README.md +16 -1
  2. package/dist/core/block/rules/attribute-line.d.ts +13 -0
  3. package/dist/core/block/rules/attribute-line.js +227 -0
  4. package/dist/core/block/rules/code-block.d.ts +2 -0
  5. package/dist/core/block/rules/code-block.js +73 -0
  6. package/dist/core/block/rules/code-fence.d.ts +15 -0
  7. package/dist/core/block/rules/code-fence.js +37 -0
  8. package/dist/core/block/rules/content-title.d.ts +12 -0
  9. package/dist/core/block/rules/content-title.js +70 -0
  10. package/dist/core/block/rules/footnotes.d.ts +9 -0
  11. package/dist/core/block/rules/footnotes.js +105 -0
  12. package/dist/core/block/rules/html.d.ts +7 -0
  13. package/dist/core/block/rules/html.js +48 -0
  14. package/dist/core/block/rules/image.d.ts +9 -0
  15. package/dist/core/block/rules/image.js +78 -0
  16. package/dist/core/block/rules/list.d.ts +3 -0
  17. package/dist/core/block/rules/list.js +275 -0
  18. package/dist/core/block/rules/paragraph.d.ts +6 -0
  19. package/dist/core/block/rules/paragraph.js +55 -0
  20. package/dist/core/block/rules/quote.d.ts +13 -0
  21. package/dist/core/block/rules/quote.js +104 -0
  22. package/dist/core/block/rules/table.d.ts +2 -0
  23. package/dist/core/block/rules/table.js +199 -0
  24. package/dist/core/block/runtime.d.ts +25 -0
  25. package/dist/core/block/runtime.js +116 -0
  26. package/dist/core/block-parser.js +183 -1322
  27. package/dist/html/convert.d.ts +8 -0
  28. package/dist/html/convert.js +22 -0
  29. package/dist/html/render/blocks.d.ts +15 -0
  30. package/dist/html/render/blocks.js +50 -6
  31. package/dist/html/render/html.d.ts +16 -0
  32. package/dist/html/render/html.js +48 -14
  33. package/dist/html/render/utils.d.ts +1 -0
  34. package/package.json +5 -1
@@ -1,6 +1,7 @@
1
1
  import { ParseOptions } from '../core/parser';
2
2
  import { JianwenDocument } from '../core/ast';
3
3
  import { ParseError } from '../core/errors';
4
+ import { RenderedBlockGroup } from './render/html';
4
5
  import { RenderHtmlOptions } from './render/utils';
5
6
  export declare const DEFAULT_RUNTIME_SRC = "dist/html/theme/runtime.js";
6
7
  export interface HtmlDocumentOptions {
@@ -25,5 +26,12 @@ export interface RenderJianwenToHtmlDocumentResult {
25
26
  ast: JianwenDocument;
26
27
  errors: ParseError[];
27
28
  }
29
+ export interface RenderJianwenToHtmlDocumentWithBlockMapResult {
30
+ html: string;
31
+ ast: JianwenDocument;
32
+ errors: ParseError[];
33
+ groups: RenderedBlockGroup[];
34
+ }
28
35
  export declare function buildHtmlDocument(bodyHtml: string, options?: HtmlDocumentOptions): string;
29
36
  export declare function renderJianwenToHtmlDocument(source: string, options?: RenderJianwenToHtmlDocumentOptions): RenderJianwenToHtmlDocumentResult;
37
+ export declare function renderJianwenToHtmlDocumentWithBlockMap(source: string, options?: RenderJianwenToHtmlDocumentOptions): RenderJianwenToHtmlDocumentWithBlockMapResult;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DEFAULT_RUNTIME_SRC = void 0;
4
4
  exports.buildHtmlDocument = buildHtmlDocument;
5
5
  exports.renderJianwenToHtmlDocument = renderJianwenToHtmlDocument;
6
+ exports.renderJianwenToHtmlDocumentWithBlockMap = renderJianwenToHtmlDocumentWithBlockMap;
6
7
  const parser_1 = require("../core/parser");
7
8
  const format_1 = require("./format");
8
9
  const html_1 = require("./render/html");
@@ -59,3 +60,24 @@ function renderJianwenToHtmlDocument(source, options = {}) {
59
60
  });
60
61
  return { html, ast: parseResult.ast, errors: parseResult.errors };
61
62
  }
63
+ function renderJianwenToHtmlDocumentWithBlockMap(source, options = {}) {
64
+ const parseResult = (0, parser_1.parseJianwenWithErrors)(source, options.parse);
65
+ const renderOptions = {
66
+ includeMeta: true,
67
+ includeComments: false,
68
+ emitBlockMeta: true,
69
+ ...options.render,
70
+ };
71
+ const rendered = (0, html_1.renderDocumentToHtmlWithBlockMap)(parseResult.ast, renderOptions);
72
+ const title = options.document?.title ?? parseResult.ast.meta?.title;
73
+ const html = buildHtmlDocument(rendered.html, {
74
+ ...options.document,
75
+ title,
76
+ });
77
+ return {
78
+ html,
79
+ ast: parseResult.ast,
80
+ errors: parseResult.errors,
81
+ groups: rendered.groups,
82
+ };
83
+ }
@@ -1,4 +1,19 @@
1
1
  import { BlockNode } from '../../core/ast';
2
2
  import { RenderHtmlOptions } from './utils';
3
+ export type RenderBlockGroupKind = 'single' | 'sameLine' | 'foldable';
4
+ export interface RenderBlockGroupDraft {
5
+ id: string;
6
+ kind: RenderBlockGroupKind;
7
+ startBlockIndex: number;
8
+ endBlockIndex: number;
9
+ startLine?: number;
10
+ origin?: string;
11
+ readOnly: boolean;
12
+ }
13
+ export interface RenderBlocksResult {
14
+ html: string;
15
+ groups: RenderBlockGroupDraft[];
16
+ }
3
17
  export declare function renderBlocksToHtml(blocks: BlockNode[], options?: RenderHtmlOptions): string;
18
+ export declare function renderBlocksToHtmlWithGroups(blocks: BlockNode[], options?: RenderHtmlOptions): RenderBlocksResult;
4
19
  export declare function renderBlockToHtml(block: BlockNode, options: RenderHtmlOptions): string;
@@ -1,18 +1,52 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.renderBlocksToHtml = renderBlocksToHtml;
4
+ exports.renderBlocksToHtmlWithGroups = renderBlocksToHtmlWithGroups;
4
5
  exports.renderBlockToHtml = renderBlockToHtml;
5
6
  const utils_1 = require("./utils");
6
7
  const inlines_1 = require("./inlines");
8
+ const location_1 = require("../../core/location");
7
9
  function renderBlocksToHtml(blocks, options = {}) {
10
+ return renderBlocksToHtmlWithGroups(blocks, options).html;
11
+ }
12
+ function renderBlocksToHtmlWithGroups(blocks, options = {}) {
8
13
  const result = [];
14
+ const groups = [];
9
15
  let i = 0;
10
- function wrapBlock(html) {
16
+ function buildGroupDraft(kind, blockList, startBlockIndex) {
17
+ const endBlockIndex = startBlockIndex + blockList.length - 1;
18
+ let startLine;
19
+ const origins = new Set();
20
+ for (const block of blockList) {
21
+ const location = (0, location_1.getNodeLocation)(block);
22
+ if (location && (startLine === undefined || location.line < startLine)) {
23
+ startLine = location.line;
24
+ }
25
+ const origin = (0, location_1.getNodeOrigin)(block);
26
+ if (origin) {
27
+ origins.add(origin);
28
+ }
29
+ }
30
+ const origin = origins.size === 1 ? Array.from(origins)[0] : undefined;
31
+ const hasIncludeBlock = blockList.some((block) => block.type === 'include');
32
+ const readOnly = origins.size > 0 || hasIncludeBlock;
33
+ return {
34
+ id: `g-${groups.length}`,
35
+ kind,
36
+ startBlockIndex,
37
+ endBlockIndex,
38
+ startLine,
39
+ origin,
40
+ readOnly,
41
+ };
42
+ }
43
+ function wrapBlock(html, group) {
11
44
  if (!html || !html.trim())
12
45
  return '';
13
46
  if (options.suppressBlockWrapper)
14
47
  return html;
15
- return `<div class="jw-block">${html}</div>`;
48
+ const dataAttr = options.emitBlockMeta && group ? ` data-jw-group-id="${(0, utils_1.escapeAttr)(group.id)}"` : '';
49
+ return `<div class="jw-block"${dataAttr}>${html}</div>`;
16
50
  }
17
51
  while (i < blocks.length) {
18
52
  const block = blocks[i];
@@ -41,13 +75,18 @@ function renderBlocksToHtml(blocks, options = {}) {
41
75
  }
42
76
  const detailsContent = foldedBlocks.join('');
43
77
  const detailsHtml = `<details class="jw-foldable-section">${headingHtml}${detailsContent}</details>`;
44
- result.push(wrapBlock(detailsHtml));
78
+ const groupBlocks = blocks.slice(i, j).filter((item) => Boolean(item));
79
+ const group = buildGroupDraft('foldable', groupBlocks, i);
80
+ groups.push(group);
81
+ result.push(wrapBlock(detailsHtml, group));
45
82
  i = j;
46
83
  continue;
47
84
  }
48
85
  const blockAttrs = 'blockAttrs' in block ? block.blockAttrs : undefined;
49
86
  if (!blockAttrs?.sameLine) {
50
- result.push(wrapBlock(renderBlockToHtml(block, options)));
87
+ const group = buildGroupDraft('single', [block], i);
88
+ groups.push(group);
89
+ result.push(wrapBlock(renderBlockToHtml(block, options), group));
51
90
  i++;
52
91
  continue;
53
92
  }
@@ -81,10 +120,15 @@ function renderBlocksToHtml(blocks, options = {}) {
81
120
  }
82
121
  }
83
122
  const rowHtml = rowBlocks.map((b) => renderBlockToHtml(b, options)).join('');
84
- result.push(wrapBlock(`<div class="jw-same-line-row">${rowHtml}</div>`));
123
+ const group = buildGroupDraft('sameLine', rowBlocks, rowStartIndex);
124
+ groups.push(group);
125
+ result.push(wrapBlock(`<div class="jw-same-line-row">${rowHtml}</div>`, group));
85
126
  i = rowStartIndex + rowBlocks.length;
86
127
  }
87
- return result.join('');
128
+ return {
129
+ html: result.join(''),
130
+ groups,
131
+ };
88
132
  }
89
133
  function renderBlockToHtml(block, options) {
90
134
  switch (block.type) {
@@ -3,6 +3,22 @@ import { RenderHtmlOptions } from './utils';
3
3
  export { RenderHtmlOptions } from './utils';
4
4
  export { DocumentTheme } from '../theme/theme';
5
5
  export { renderBlocksToHtml } from './blocks';
6
+ export { renderBlocksToHtmlWithGroups } from './blocks';
6
7
  export { renderInlinesToHtml } from './inlines';
8
+ export interface RenderedBlockGroup {
9
+ id: string;
10
+ kind: 'single' | 'sameLine' | 'foldable';
11
+ startBlockIndex: number;
12
+ endBlockIndex: number;
13
+ startLine?: number;
14
+ endLine?: number;
15
+ origin?: string;
16
+ readOnly: boolean;
17
+ }
18
+ export interface RenderDocumentWithBlockMapResult {
19
+ html: string;
20
+ groups: RenderedBlockGroup[];
21
+ }
7
22
  export declare function createDefaultAssetPathResolver(sourceFilePath: string, outputFilePath: string): (assetPath: string) => string | undefined;
8
23
  export declare function renderDocumentToHtml(doc: JianwenDocument, options?: RenderHtmlOptions): string;
24
+ export declare function renderDocumentToHtmlWithBlockMap(doc: JianwenDocument, options?: RenderHtmlOptions): RenderDocumentWithBlockMapResult;
@@ -33,9 +33,10 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.renderInlinesToHtml = exports.renderBlocksToHtml = void 0;
36
+ exports.renderInlinesToHtml = exports.renderBlocksToHtmlWithGroups = exports.renderBlocksToHtml = void 0;
37
37
  exports.createDefaultAssetPathResolver = createDefaultAssetPathResolver;
38
38
  exports.renderDocumentToHtml = renderDocumentToHtml;
39
+ exports.renderDocumentToHtmlWithBlockMap = renderDocumentToHtmlWithBlockMap;
39
40
  const path = __importStar(require("path"));
40
41
  const format_1 = require("../format");
41
42
  const utils_1 = require("./utils");
@@ -43,6 +44,8 @@ const meta_1 = require("./meta");
43
44
  const blocks_1 = require("./blocks");
44
45
  var blocks_2 = require("./blocks");
45
46
  Object.defineProperty(exports, "renderBlocksToHtml", { enumerable: true, get: function () { return blocks_2.renderBlocksToHtml; } });
47
+ var blocks_3 = require("./blocks");
48
+ Object.defineProperty(exports, "renderBlocksToHtmlWithGroups", { enumerable: true, get: function () { return blocks_3.renderBlocksToHtmlWithGroups; } });
46
49
  var inlines_1 = require("./inlines");
47
50
  Object.defineProperty(exports, "renderInlinesToHtml", { enumerable: true, get: function () { return inlines_1.renderInlinesToHtml; } });
48
51
  function createDefaultAssetPathResolver(sourceFilePath, outputFilePath) {
@@ -58,6 +61,25 @@ function createDefaultAssetPathResolver(sourceFilePath, outputFilePath) {
58
61
  };
59
62
  }
60
63
  function renderDocumentToHtml(doc, options = {}) {
64
+ return renderDocumentToHtmlWithBlockMap(doc, {
65
+ ...options,
66
+ emitBlockMeta: options.emitBlockMeta ?? false,
67
+ }).html;
68
+ }
69
+ function finalizeGroups(groups, sourceLineCount) {
70
+ return groups.map((group, index) => {
71
+ const next = groups[index + 1];
72
+ let endLine = sourceLineCount;
73
+ if (next?.startLine !== undefined) {
74
+ endLine = Math.max(1, next.startLine - 1);
75
+ }
76
+ return {
77
+ ...group,
78
+ endLine: group.startLine !== undefined ? endLine : undefined,
79
+ };
80
+ });
81
+ }
82
+ function renderDocumentToHtmlWithBlockMap(doc, options = {}) {
61
83
  const wrapperTag = options.documentWrapperTag === undefined ? 'article' : options.documentWrapperTag;
62
84
  const finalOptions = { ...options };
63
85
  if (options.sourceFilePath && options.outputFilePath && !options.resolveAssetPath) {
@@ -68,22 +90,34 @@ function renderDocumentToHtml(doc, options = {}) {
68
90
  innerParts.push((0, meta_1.renderMetaToHtml)(doc.meta));
69
91
  }
70
92
  if (!wrapperTag) {
71
- innerParts.push((0, blocks_1.renderBlocksToHtml)(doc.children, {
93
+ const rendered = (0, blocks_1.renderBlocksToHtmlWithGroups)(doc.children, {
72
94
  ...finalOptions,
73
95
  suppressBlockWrapper: true,
74
- }));
96
+ emitBlockMeta: finalOptions.emitBlockMeta ?? true,
97
+ });
98
+ const lineCount = doc.source ? doc.source.split('\n').length : undefined;
99
+ innerParts.push(rendered.html);
100
+ return {
101
+ html: innerParts.join(''),
102
+ groups: finalizeGroups(rendered.groups, lineCount),
103
+ };
75
104
  }
76
105
  else {
77
- innerParts.push((0, blocks_1.renderBlocksToHtml)(doc.children, finalOptions));
78
- }
79
- const innerHtml = innerParts.join('');
80
- if (!wrapperTag) {
81
- return innerHtml;
106
+ const rendered = (0, blocks_1.renderBlocksToHtmlWithGroups)(doc.children, {
107
+ ...finalOptions,
108
+ emitBlockMeta: finalOptions.emitBlockMeta ?? true,
109
+ });
110
+ innerParts.push(rendered.html);
111
+ const innerHtml = innerParts.join('');
112
+ const wrapperAttrs = (0, meta_1.buildDocumentWrapperAttributes)(doc.meta);
113
+ const themeAttr = finalOptions.documentTheme
114
+ ? ` data-jw-theme="${(0, utils_1.escapeAttr)(finalOptions.documentTheme)}"`
115
+ : '';
116
+ const html = `<${wrapperTag} class="jw-root"${wrapperAttrs}${themeAttr}>${innerHtml}</${wrapperTag}>`;
117
+ const lineCount = doc.source ? doc.source.split('\n').length : undefined;
118
+ return {
119
+ html: finalOptions.format ? (0, format_1.formatHtml)(html) : html,
120
+ groups: finalizeGroups(rendered.groups, lineCount),
121
+ };
82
122
  }
83
- const wrapperAttrs = (0, meta_1.buildDocumentWrapperAttributes)(doc.meta);
84
- const themeAttr = finalOptions.documentTheme
85
- ? ` data-jw-theme="${(0, utils_1.escapeAttr)(finalOptions.documentTheme)}"`
86
- : '';
87
- const html = `<${wrapperTag} class="jw-root"${wrapperAttrs}${themeAttr}>${innerHtml}</${wrapperTag}>`;
88
- return finalOptions.format ? (0, format_1.formatHtml)(html) : html;
89
123
  }
@@ -3,6 +3,7 @@ import { DocumentTheme } from '../theme/theme';
3
3
  export interface RenderHtmlOptions {
4
4
  includeMeta?: boolean;
5
5
  includeComments?: boolean;
6
+ emitBlockMeta?: boolean;
6
7
  resolveHtmlSource?: (source: string) => string | undefined;
7
8
  resolveInclude?: (mode: 'file' | 'tag', target: string) => string | undefined;
8
9
  resolveAssetPath?: (assetPath: string) => string | undefined;
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "@jianwen-lang/parser",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "JianWen language parser implemented in TypeScript",
5
5
  "main": "dist/parser.js",
6
6
  "types": "dist/parser.d.ts",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/Jianwen-lang/parser.git"
10
+ },
7
11
  "publishConfig": {
8
12
  "access": "public"
9
13
  },