@wdprlib/parser 3.2.0 → 4.0.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/dist/index.cjs +10451 -8402
- package/dist/index.d.cts +313 -337
- package/dist/index.d.ts +313 -337
- package/dist/index.js +10438 -8389
- package/package.json +1 -1
- package/src/index.ts +7 -0
- package/src/lexer/anchor.ts +48 -0
- package/src/lexer/index.ts +3 -2
- package/src/lexer/lexer.ts +73 -559
- package/src/lexer/options.ts +19 -0
- package/src/lexer/punctuation.ts +70 -0
- package/src/lexer/quoted-string.ts +16 -0
- package/src/lexer/runs.ts +85 -0
- package/src/lexer/spacing-actions.ts +24 -0
- package/src/lexer/state.ts +103 -0
- package/src/lexer/syntax-actions.ts +80 -0
- package/src/lexer/text-actions.ts +41 -0
- package/src/lexer/token-actions.ts +136 -0
- package/src/lexer/token-factory.ts +62 -0
- package/src/lexer/tokenize.ts +18 -0
- package/src/parser/constants.ts +2 -0
- package/src/parser/depth/index.ts +111 -0
- package/src/parser/depth/stack.ts +82 -0
- package/src/parser/parse/block.ts +42 -0
- package/src/parser/parse/context.ts +26 -0
- package/src/parser/parse/footnotes.ts +25 -0
- package/src/parser/parse/index.ts +42 -0
- package/src/parser/parse/options.ts +34 -0
- package/src/parser/parse/parser.ts +79 -0
- package/src/parser/parse/plain-non-ascii.ts +129 -0
- package/src/parser/parse/result.ts +57 -0
- package/src/parser/parse/source.ts +11 -0
- package/src/parser/postprocess/divAdjacentParagraph.ts +1 -1
- package/src/parser/postprocess/spanStrip/clean-element.ts +168 -0
- package/src/parser/postprocess/spanStrip/cleanup.ts +25 -0
- package/src/parser/postprocess/spanStrip/empty-spans.ts +36 -0
- package/src/parser/postprocess/spanStrip/escaped.ts +78 -0
- package/src/parser/postprocess/spanStrip/factory.ts +23 -0
- package/src/parser/postprocess/spanStrip/index.ts +8 -0
- package/src/parser/postprocess/spanStrip/merge.ts +117 -0
- package/src/parser/postprocess/spanStrip/predicates.ts +59 -0
- package/src/parser/postprocess/spanStrip/split.ts +67 -0
- package/src/parser/preprocess/expr/chars.ts +15 -0
- package/src/parser/preprocess/expr/evaluate.ts +22 -0
- package/src/parser/preprocess/expr/index.ts +45 -0
- package/src/parser/preprocess/expr/kind.ts +19 -0
- package/src/parser/preprocess/expr/parse.ts +103 -0
- package/src/parser/preprocess/expr/scan.ts +34 -0
- package/src/parser/preprocess/expr/types.ts +14 -0
- package/src/parser/preprocess/typography.ts +70 -5
- package/src/parser/preprocess/utils/bracket-depths.ts +98 -0
- package/src/parser/preprocess/utils/index.ts +13 -0
- package/src/parser/preprocess/utils/raw-regions.ts +153 -0
- package/src/parser/preprocess/whitespace/detection.ts +39 -0
- package/src/parser/preprocess/whitespace/index.ts +79 -0
- package/src/parser/preprocess/whitespace/leading-spaces.ts +11 -0
- package/src/parser/preprocess/whitespace/patterns.ts +23 -0
- package/src/parser/rules/block/align/body.ts +46 -0
- package/src/parser/rules/block/align/element.ts +13 -0
- package/src/parser/rules/block/align/index.ts +90 -0
- package/src/parser/rules/block/align/syntax.ts +113 -0
- package/src/parser/rules/block/bibliography/body.ts +81 -0
- package/src/parser/rules/block/bibliography/entries.ts +49 -0
- package/src/parser/rules/block/bibliography/entry-content.ts +73 -0
- package/src/parser/rules/block/bibliography/entry-key.ts +83 -0
- package/src/parser/rules/block/bibliography/index.ts +90 -0
- package/src/parser/rules/block/bibliography/open.ts +53 -0
- package/src/parser/rules/block/block-list/bare-content.ts +105 -0
- package/src/parser/rules/block/block-list/bare-paragraph.ts +60 -0
- package/src/parser/rules/block/block-list/index.ts +51 -0
- package/src/parser/rules/block/block-list/item-content.ts +132 -0
- package/src/parser/rules/block/block-list/li-content.ts +107 -0
- package/src/parser/rules/block/block-list/li-item.ts +77 -0
- package/src/parser/rules/block/block-list/list-block.ts +100 -0
- package/src/parser/rules/block/block-list/open.ts +51 -0
- package/src/parser/rules/block/block-list/tags.ts +50 -0
- package/src/parser/rules/block/blockquote/build.ts +62 -0
- package/src/parser/rules/block/blockquote/index.ts +80 -0
- package/src/parser/rules/block/blockquote/line.ts +79 -0
- package/src/parser/rules/block/blockquote/lines.ts +39 -0
- package/src/parser/rules/block/{center.ts → center/index.ts} +7 -22
- package/src/parser/rules/block/center/open.ts +27 -0
- package/src/parser/rules/block/{clear-float.ts → clear-float/index.ts} +6 -30
- package/src/parser/rules/block/clear-float/syntax.ts +43 -0
- package/src/parser/rules/block/code/attributes.ts +30 -0
- package/src/parser/rules/block/code/content.ts +57 -0
- package/src/parser/rules/block/code/index.ts +100 -0
- package/src/parser/rules/block/collapsible/attributes.ts +95 -0
- package/src/parser/rules/block/collapsible/body.ts +69 -0
- package/src/parser/rules/block/collapsible/index.ts +117 -0
- package/src/parser/rules/block/collapsible/open.ts +51 -0
- package/src/parser/rules/block/collapsible/orphans.ts +31 -0
- package/src/parser/rules/block/collapsible/tags.ts +17 -0
- package/src/parser/rules/block/comment/consume.ts +37 -0
- package/src/parser/rules/block/{comment.ts → comment/index.ts} +12 -38
- package/src/parser/rules/block/{content-separator.ts → content-separator/index.ts} +5 -35
- package/src/parser/rules/block/content-separator/syntax.ts +33 -0
- package/src/parser/rules/block/definition-list/collect.ts +40 -0
- package/src/parser/rules/block/definition-list/index.ts +63 -0
- package/src/parser/rules/block/definition-list/item-key.ts +95 -0
- package/src/parser/rules/block/definition-list/item-value.ts +56 -0
- package/src/parser/rules/block/definition-list/items.ts +54 -0
- package/src/parser/rules/block/div/body.ts +41 -0
- package/src/parser/rules/block/div/close.ts +41 -0
- package/src/parser/rules/block/div/failed.ts +117 -0
- package/src/parser/rules/block/div/index.ts +112 -0
- package/src/parser/rules/block/div/nesting.ts +37 -0
- package/src/parser/rules/block/div/open.ts +59 -0
- package/src/parser/rules/block/div/paragraph-strip.ts +44 -0
- package/src/parser/rules/block/embed-block/content.ts +53 -0
- package/src/parser/rules/block/embed-block/index.ts +91 -0
- package/src/parser/rules/block/embed-block/open.ts +52 -0
- package/src/parser/rules/block/embed-block/tags.ts +5 -0
- package/src/parser/rules/block/footnoteblock/attributes.ts +73 -0
- package/src/parser/rules/block/footnoteblock/index.ts +82 -0
- package/src/parser/rules/block/footnoteblock/open.ts +53 -0
- package/src/parser/rules/block/heading/index.ts +87 -0
- package/src/parser/rules/block/heading/open.ts +50 -0
- package/src/parser/rules/block/heading/toc-text.ts +26 -0
- package/src/parser/rules/block/{horizontal-rule.ts → horizontal-rule/index.ts} +4 -21
- package/src/parser/rules/block/horizontal-rule/syntax.ts +21 -0
- package/src/parser/rules/block/html/body.ts +114 -0
- package/src/parser/rules/block/html/diagnostics.ts +11 -0
- package/src/parser/rules/block/html/index.ts +95 -0
- package/src/parser/rules/block/html/open.ts +36 -0
- package/src/parser/rules/block/iframe/attributes.ts +106 -0
- package/src/parser/rules/block/iframe/index.ts +73 -0
- package/src/parser/rules/block/iframe/open.ts +58 -0
- package/src/parser/rules/block/iframe/source.ts +24 -0
- package/src/parser/rules/block/iframe/url.ts +38 -0
- package/src/parser/rules/block/iftags/body.ts +48 -0
- package/src/parser/rules/block/iftags/condition.ts +24 -0
- package/src/parser/rules/block/{iftags.ts → iftags/index.ts} +16 -58
- package/src/parser/rules/block/include/arguments.ts +48 -0
- package/src/parser/rules/block/include/index.ts +75 -0
- package/src/parser/rules/block/include/location.ts +24 -0
- package/src/parser/rules/block/include/variables.ts +37 -0
- package/src/parser/rules/block/list/index.ts +73 -0
- package/src/parser/rules/block/list/line.ts +77 -0
- package/src/parser/rules/block/list/native.ts +89 -0
- package/src/parser/rules/block/math/content.ts +54 -0
- package/src/parser/rules/block/math/index.ts +106 -0
- package/src/parser/rules/block/math/name.ts +35 -0
- package/src/parser/rules/block/module/body.ts +92 -0
- package/src/parser/rules/block/module/element.ts +33 -0
- package/src/parser/rules/block/module/include/directive.ts +91 -0
- package/src/parser/rules/block/module/include/index.ts +11 -2
- package/src/parser/rules/block/module/include/references.ts +42 -0
- package/src/parser/rules/block/module/include/resolve/cache.ts +44 -0
- package/src/parser/rules/block/module/include/resolve/index.ts +106 -0
- package/src/parser/rules/block/module/include/resolve/iterate.ts +202 -0
- package/src/parser/rules/block/module/include/resolve/replace.ts +31 -0
- package/src/parser/rules/block/module/include/resolve/types.ts +105 -0
- package/src/parser/rules/block/module/include/scanner.ts +121 -0
- package/src/parser/rules/block/module/index.ts +14 -2
- package/src/parser/rules/block/module/listpages/compiler.ts +12 -392
- package/src/parser/rules/block/module/listpages/extract.ts +25 -359
- package/src/parser/rules/block/module/listpages/extraction/listpages.ts +42 -0
- package/src/parser/rules/block/module/listpages/extraction/listusers.ts +30 -0
- package/src/parser/rules/block/module/listpages/extraction/query.ts +51 -0
- package/src/parser/rules/block/module/listpages/extraction/result.ts +18 -0
- package/src/parser/rules/block/module/listpages/extraction/template.ts +96 -0
- package/src/parser/rules/block/module/listpages/extraction/variables.ts +58 -0
- package/src/parser/rules/block/module/listpages/normalization/date-selector.ts +53 -0
- package/src/parser/rules/block/module/listpages/normalization/numeric-selector.ts +32 -0
- package/src/parser/rules/block/module/listpages/normalization/order-parent.ts +82 -0
- package/src/parser/rules/block/module/listpages/normalization/selectors.ts +2 -0
- package/src/parser/rules/block/module/listpages/normalization/tags-category.ts +86 -0
- package/src/parser/rules/block/module/listpages/normalize.ts +8 -324
- package/src/parser/rules/block/module/listpages/resolution/items.ts +43 -0
- package/src/parser/rules/block/module/listpages/resolution/wrapper.ts +42 -0
- package/src/parser/rules/block/module/listpages/resolve.ts +5 -75
- package/src/parser/rules/block/module/listpages/template/format/content.ts +41 -0
- package/src/parser/rules/block/module/listpages/template/format/date.ts +116 -0
- package/src/parser/rules/block/module/listpages/template/format/index.ts +4 -0
- package/src/parser/rules/block/module/listpages/template/format/tags.ts +7 -0
- package/src/parser/rules/block/module/listpages/template/format/user.ts +9 -0
- package/src/parser/rules/block/module/listpages/template/getters/index.ts +36 -0
- package/src/parser/rules/block/module/listpages/template/getters/parameterized.ts +60 -0
- package/src/parser/rules/block/module/listpages/template/getters/simple.ts +65 -0
- package/src/parser/rules/block/module/listpages/template/getters/types.ts +3 -0
- package/src/parser/rules/block/module/listpages/template/syntax.ts +97 -0
- package/src/parser/rules/block/module/listpages/types/data-fetcher.ts +15 -0
- package/src/parser/rules/block/module/listpages/types/data-requirements.ts +52 -0
- package/src/parser/rules/block/module/listpages/types/external-data.ts +77 -0
- package/src/parser/rules/block/module/listpages/types/index.ts +17 -0
- package/src/parser/rules/block/module/listpages/types/normalized-query.ts +120 -0
- package/src/parser/rules/block/module/listpages/types/query.ts +67 -0
- package/src/parser/rules/block/module/listpages/types/template.ts +17 -0
- package/src/parser/rules/block/module/listpages/types/variables.ts +69 -0
- package/src/parser/rules/block/module/listpages/url-resolution/fields.ts +48 -0
- package/src/parser/rules/block/module/listpages/url-resolution/params.ts +19 -0
- package/src/parser/rules/block/module/listpages/url-resolution/query.ts +24 -0
- package/src/parser/rules/block/module/listpages/url-resolution/resolve.ts +53 -0
- package/src/parser/rules/block/module/listpages/url-resolution/value.ts +25 -0
- package/src/parser/rules/block/module/listpages/url-resolver.ts +3 -160
- package/src/parser/rules/block/module/listusers/compiler.ts +4 -25
- package/src/parser/rules/block/module/listusers/extract.ts +4 -9
- package/src/parser/rules/block/module/listusers/getters.ts +21 -0
- package/src/parser/rules/block/module/listusers/variables.ts +15 -0
- package/src/parser/rules/block/module/open.ts +57 -0
- package/src/parser/rules/block/module/resolution/contexts.ts +78 -0
- package/src/parser/rules/block/module/resolution/data-maps.ts +39 -0
- package/src/parser/rules/block/module/resolution/dynamic-modules.ts +93 -0
- package/src/parser/rules/block/module/resolution/styles.ts +53 -0
- package/src/parser/rules/block/module/resolution/walk-resolve.ts +107 -0
- package/src/parser/rules/block/module/resolve.ts +79 -292
- package/src/parser/rules/block/module/rule.ts +56 -0
- package/src/parser/rules/block/module/types-common.ts +11 -0
- package/src/parser/rules/block/module/walk/children.ts +35 -0
- package/src/parser/rules/block/module/walk/index.ts +9 -0
- package/src/parser/rules/block/module/walk/map/index.ts +2 -0
- package/src/parser/rules/block/module/walk/map/stateful-definition-list.ts +25 -0
- package/src/parser/rules/block/module/walk/map/stateful-list.ts +40 -0
- package/src/parser/rules/block/module/walk/map/stateful-table.ts +23 -0
- package/src/parser/rules/block/module/walk/map/stateful-tabs.ts +19 -0
- package/src/parser/rules/block/module/walk/map/stateful.ts +71 -0
- package/src/parser/rules/block/module/walk/map/stateless-definition-list.ts +12 -0
- package/src/parser/rules/block/module/walk/map/stateless-list.ts +29 -0
- package/src/parser/rules/block/module/walk/map/stateless-table.ts +11 -0
- package/src/parser/rules/block/module/walk/map/stateless-tabs.ts +5 -0
- package/src/parser/rules/block/module/walk/map/stateless.ts +51 -0
- package/src/parser/rules/block/module/walk/map/types.ts +6 -0
- package/src/parser/rules/block/module/walk/traverse.ts +65 -0
- package/src/parser/rules/block/orphan-li/content.ts +60 -0
- package/src/parser/rules/block/orphan-li/index.ts +75 -0
- package/src/parser/rules/block/orphan-li/open.ts +25 -0
- package/src/parser/rules/block/orphan-li/tags.ts +40 -0
- package/src/parser/rules/block/paragraph/content.ts +12 -0
- package/src/parser/rules/block/paragraph/index.ts +60 -0
- package/src/parser/rules/block/paragraph/normalize.ts +52 -0
- package/src/parser/rules/block/paragraph/span-markers.ts +52 -0
- package/src/parser/rules/block/parsing/attributes/index.ts +32 -0
- package/src/parser/rules/block/parsing/attributes/names.ts +93 -0
- package/src/parser/rules/block/parsing/attributes/scanner.ts +75 -0
- package/src/parser/rules/block/parsing/attributes/values.ts +26 -0
- package/src/parser/rules/block/parsing/block-item.ts +29 -0
- package/src/parser/rules/block/parsing/content.ts +127 -0
- package/src/parser/rules/block/parsing/end-condition.ts +51 -0
- package/src/parser/rules/block/parsing/inline-content.ts +105 -0
- package/src/parser/rules/block/parsing/inline-newline.ts +41 -0
- package/src/parser/rules/block/parsing/non-boundary.ts +24 -0
- package/src/parser/rules/block/parsing/rule-dispatch.ts +44 -0
- package/src/parser/rules/block/table/index.ts +80 -0
- package/src/parser/rules/block/table/pipe/cell-start.ts +69 -0
- package/src/parser/rules/block/table/pipe/cell.ts +106 -0
- package/src/parser/rules/block/table/pipe/index.ts +2 -0
- package/src/parser/rules/block/table/pipe/row.ts +88 -0
- package/src/parser/rules/block/table/pipe/tokens.ts +14 -0
- package/src/parser/rules/block/table/pipe/trim.ts +50 -0
- package/src/parser/rules/block/table-block/body.ts +79 -0
- package/src/parser/rules/block/table-block/cell-attributes.ts +33 -0
- package/src/parser/rules/block/table-block/cell-boundary.ts +99 -0
- package/src/parser/rules/block/table-block/cell-content/index.ts +88 -0
- package/src/parser/rules/block/table-block/cell-content/segments.ts +134 -0
- package/src/parser/rules/block/table-block/cell-newline.ts +47 -0
- package/src/parser/rules/block/table-block/cell.ts +64 -0
- package/src/parser/rules/block/table-block/index.ts +113 -0
- package/src/parser/rules/block/table-block/row-boundary.ts +75 -0
- package/src/parser/rules/block/table-block/structure.ts +80 -0
- package/src/parser/rules/block/tabview/body.ts +64 -0
- package/src/parser/rules/block/tabview/index.ts +90 -0
- package/src/parser/rules/block/tabview/open.ts +50 -0
- package/src/parser/rules/block/tabview/tab.ts +92 -0
- package/src/parser/rules/block/tabview/tags.ts +30 -0
- package/src/parser/rules/block/toc/element.ts +11 -0
- package/src/parser/rules/block/toc/index.ts +44 -0
- package/src/parser/rules/block/toc/open.ts +84 -0
- package/src/parser/rules/block/utils.ts +10 -610
- package/src/parser/rules/{utils.ts → common/attribute-safety.ts} +3 -49
- package/src/parser/rules/common/block-name.ts +33 -0
- package/src/parser/rules/common/index.ts +2 -0
- package/src/parser/rules/contracts/index.ts +3 -0
- package/src/parser/rules/contracts/parse-context.ts +38 -0
- package/src/parser/rules/contracts/rule.ts +43 -0
- package/src/parser/rules/contracts/scope.ts +31 -0
- package/src/parser/rules/inline/anchor/attributes.ts +54 -0
- package/src/parser/rules/inline/anchor/child.ts +26 -0
- package/src/parser/rules/inline/anchor/close.ts +34 -0
- package/src/parser/rules/inline/anchor/content.ts +59 -0
- package/src/parser/rules/inline/anchor/index.ts +103 -0
- package/src/parser/rules/inline/anchor/newline.ts +26 -0
- package/src/parser/rules/inline/anchor/open.ts +47 -0
- package/src/parser/rules/inline/anchor/paragraph-strip.ts +14 -0
- package/src/parser/rules/inline/anchor/syntax.ts +40 -0
- package/src/parser/rules/inline/anchor-name/index.ts +38 -0
- package/src/parser/rules/inline/anchor-name/name.ts +39 -0
- package/src/parser/rules/inline/anchor-name/syntax.ts +46 -0
- package/src/parser/rules/inline/bibcite/element.ts +14 -0
- package/src/parser/rules/inline/bibcite/index.ts +34 -0
- package/src/parser/rules/inline/bibcite/syntax.ts +64 -0
- package/src/parser/rules/inline/bold.ts +2 -39
- package/src/parser/rules/inline/color/index.ts +35 -0
- package/src/parser/rules/inline/color/syntax.ts +69 -0
- package/src/parser/rules/inline/comment/consume.ts +31 -0
- package/src/parser/rules/inline/{comment.ts → comment/index.ts} +10 -36
- package/src/parser/rules/inline/equation-ref/element.ts +8 -0
- package/src/parser/rules/inline/equation-ref/index.ts +34 -0
- package/src/parser/rules/inline/equation-ref/syntax.ts +45 -0
- package/src/parser/rules/inline/expr/branch.ts +104 -0
- package/src/parser/rules/inline/expr/conditional-branch.ts +27 -0
- package/src/parser/rules/inline/expr/conditional.ts +80 -0
- package/src/parser/rules/inline/expr/depth.ts +25 -0
- package/src/parser/rules/inline/expr/elements.ts +39 -0
- package/src/parser/rules/inline/expr/index.ts +84 -0
- package/src/parser/rules/inline/expr/syntax.ts +45 -0
- package/src/parser/rules/inline/footnote/child.ts +22 -0
- package/src/parser/rules/inline/footnote/close.ts +33 -0
- package/src/parser/rules/inline/footnote/content.ts +54 -0
- package/src/parser/rules/inline/footnote/elements.ts +38 -0
- package/src/parser/rules/inline/footnote/index.ts +54 -0
- package/src/parser/rules/inline/footnote/newline.ts +27 -0
- package/src/parser/rules/inline/footnote/open.ts +38 -0
- package/src/parser/rules/inline/formatting/container.ts +50 -0
- package/src/parser/rules/inline/{guillemet.ts → guillemet/index.ts} +5 -13
- package/src/parser/rules/inline/guillemet/text.ts +11 -0
- package/src/parser/rules/inline/html/gate.ts +64 -0
- package/src/parser/rules/inline/{html.ts → html/index.ts} +9 -60
- package/src/parser/rules/inline/html/open.ts +37 -0
- package/src/parser/rules/inline/image/attributes.ts +22 -0
- package/src/parser/rules/inline/image/body.ts +36 -0
- package/src/parser/rules/inline/image/index.ts +89 -0
- package/src/parser/rules/inline/image/open.ts +56 -0
- package/src/parser/rules/inline/image/source.ts +62 -0
- package/src/parser/rules/inline/image/syntax.ts +76 -0
- package/src/parser/rules/inline/italic.ts +2 -30
- package/src/parser/rules/inline/line-break/backslash.ts +58 -0
- package/src/parser/rules/inline/line-break/elements.ts +9 -0
- package/src/parser/rules/inline/line-break/index.ts +3 -0
- package/src/parser/rules/inline/line-break/newline.ts +82 -0
- package/src/parser/rules/inline/line-break/underscore.ts +45 -0
- package/src/parser/rules/inline/link-anchor.ts +6 -81
- package/src/parser/rules/inline/link-bracket/anchor.ts +3 -0
- package/src/parser/rules/inline/link-bracket/direct-url.ts +5 -0
- package/src/parser/rules/inline/link-bracket/parsed.ts +81 -0
- package/src/parser/rules/inline/link-bracket/parts.ts +64 -0
- package/src/parser/rules/inline/link-bracket/prefix.ts +15 -0
- package/src/parser/rules/inline/link-single.ts +7 -98
- package/src/parser/rules/inline/link-star.ts +7 -69
- package/src/parser/rules/inline/link-triple/fallback.ts +10 -0
- package/src/parser/rules/inline/link-triple/index.ts +62 -0
- package/src/parser/rules/inline/link-triple/interwiki.ts +11 -0
- package/src/parser/rules/inline/link-triple/label.ts +35 -0
- package/src/parser/rules/inline/link-triple/syntax.ts +72 -0
- package/src/parser/rules/inline/link-triple/target.ts +36 -0
- package/src/parser/rules/inline/math-inline/index.ts +40 -0
- package/src/parser/rules/inline/math-inline/syntax.ts +55 -0
- package/src/parser/rules/inline/monospace.ts +2 -30
- package/src/parser/rules/inline/parsing/block-boundary.ts +42 -0
- package/src/parser/rules/inline/parsing/block-start-predicates.ts +117 -0
- package/src/parser/rules/inline/parsing/collect.ts +23 -0
- package/src/parser/rules/inline/parsing/inline-content.ts +115 -0
- package/src/parser/rules/inline/parsing/paragraph-boundary.ts +47 -0
- package/src/parser/rules/inline/parsing/plain-text.ts +69 -0
- package/src/parser/rules/inline/parsing/preserved-line-break.ts +11 -0
- package/src/parser/rules/inline/parsing/rules.ts +34 -0
- package/src/parser/rules/inline/parsing/simple-token.ts +26 -0
- package/src/parser/rules/inline/raw/angle.ts +40 -0
- package/src/parser/rules/inline/raw/double-at.ts +78 -0
- package/src/parser/rules/inline/raw/index.ts +26 -0
- package/src/parser/rules/inline/raw/result.ts +26 -0
- package/src/parser/rules/inline/size/content.ts +65 -0
- package/src/parser/rules/inline/size/index.ts +55 -0
- package/src/parser/rules/inline/size/open.ts +43 -0
- package/src/parser/rules/inline/size/value.ts +45 -0
- package/src/parser/rules/inline/span/content.ts +97 -0
- package/src/parser/rules/inline/span/elements.ts +108 -0
- package/src/parser/rules/inline/span/index.ts +79 -0
- package/src/parser/rules/inline/span/newline.ts +50 -0
- package/src/parser/rules/inline/span/syntax.ts +70 -0
- package/src/parser/rules/inline/{strikethrough.ts → strikethrough/index.ts} +5 -60
- package/src/parser/rules/inline/strikethrough/parse.ts +14 -0
- package/src/parser/rules/inline/strikethrough/syntax.ts +24 -0
- package/src/parser/rules/inline/subscript.ts +2 -39
- package/src/parser/rules/inline/superscript.ts +4 -39
- package/src/parser/rules/inline/text/element.ts +5 -0
- package/src/parser/rules/inline/{text.ts → text/index.ts} +5 -4
- package/src/parser/rules/inline/underline/child.ts +26 -0
- package/src/parser/rules/inline/underline/content.ts +29 -0
- package/src/parser/rules/inline/{underline.ts → underline/index.ts} +6 -49
- package/src/parser/rules/inline/user/element.ts +11 -0
- package/src/parser/rules/inline/user/index.ts +34 -0
- package/src/parser/rules/inline/user/syntax.ts +67 -0
- package/src/parser/rules/inline/utils.ts +4 -344
- package/src/parser/rules/tokens.ts +106 -0
- package/src/parser/rules/types.ts +9 -252
- package/src/parser/depth.ts +0 -251
- package/src/parser/parse.ts +0 -315
- package/src/parser/postprocess/spanStrip.ts +0 -697
- package/src/parser/preprocess/expr.ts +0 -265
- package/src/parser/preprocess/utils.ts +0 -250
- package/src/parser/preprocess/whitespace.ts +0 -111
- package/src/parser/rules/block/align.ts +0 -282
- package/src/parser/rules/block/bibliography.ts +0 -359
- package/src/parser/rules/block/block-list.ts +0 -689
- package/src/parser/rules/block/blockquote.ts +0 -238
- package/src/parser/rules/block/code.ts +0 -187
- package/src/parser/rules/block/collapsible.ts +0 -337
- package/src/parser/rules/block/definition-list.ts +0 -270
- package/src/parser/rules/block/div.ts +0 -400
- package/src/parser/rules/block/embed-block.ts +0 -153
- package/src/parser/rules/block/footnoteblock.ts +0 -200
- package/src/parser/rules/block/heading.ts +0 -142
- package/src/parser/rules/block/html.ts +0 -222
- package/src/parser/rules/block/iframe.ts +0 -239
- package/src/parser/rules/block/include.ts +0 -179
- package/src/parser/rules/block/list.ts +0 -244
- package/src/parser/rules/block/math.ts +0 -183
- package/src/parser/rules/block/module/include/resolve.ts +0 -556
- package/src/parser/rules/block/module/listpages/types.ts +0 -513
- package/src/parser/rules/block/module/walk.ts +0 -380
- package/src/parser/rules/block/module.ts +0 -164
- package/src/parser/rules/block/orphan-li.ts +0 -177
- package/src/parser/rules/block/paragraph.ts +0 -157
- package/src/parser/rules/block/table-block.ts +0 -726
- package/src/parser/rules/block/table.ts +0 -441
- package/src/parser/rules/block/tabview.ts +0 -331
- package/src/parser/rules/block/toc.ts +0 -129
- package/src/parser/rules/inline/anchor-name.ts +0 -154
- package/src/parser/rules/inline/anchor.ts +0 -327
- package/src/parser/rules/inline/bibcite.ts +0 -153
- package/src/parser/rules/inline/color.ts +0 -140
- package/src/parser/rules/inline/equation-ref.ts +0 -115
- package/src/parser/rules/inline/expr.ts +0 -526
- package/src/parser/rules/inline/footnote.ts +0 -223
- package/src/parser/rules/inline/image.ts +0 -328
- package/src/parser/rules/inline/line-break.ts +0 -326
- package/src/parser/rules/inline/link-triple.ts +0 -267
- package/src/parser/rules/inline/math-inline.ts +0 -126
- package/src/parser/rules/inline/raw.ts +0 -262
- package/src/parser/rules/inline/size.ts +0 -244
- package/src/parser/rules/inline/span.ts +0 -424
- package/src/parser/rules/inline/user.ts +0 -147
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ParseContext } from "../types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Parse block name from tokens (handles [[name or [[/name).
|
|
5
|
+
*
|
|
6
|
+
* Handles underscore suffix like "div_" which may be tokenized as
|
|
7
|
+
* [IDENTIFIER "div"] [UNDERSCORE "_"].
|
|
8
|
+
*/
|
|
9
|
+
export function parseBlockName(
|
|
10
|
+
ctx: ParseContext,
|
|
11
|
+
startPos: number,
|
|
12
|
+
): { name: string; consumed: number } | null {
|
|
13
|
+
let pos = startPos;
|
|
14
|
+
let consumed = 0;
|
|
15
|
+
|
|
16
|
+
// Wikidot does NOT allow whitespace between [[ and block name.
|
|
17
|
+
// e.g. [[ code ]] is treated as plain text, not a code block.
|
|
18
|
+
const token = ctx.tokens[pos];
|
|
19
|
+
if (!token || (token.type !== "TEXT" && token.type !== "IDENTIFIER")) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let name = token.value.toLowerCase();
|
|
24
|
+
consumed++;
|
|
25
|
+
pos++;
|
|
26
|
+
|
|
27
|
+
if (ctx.tokens[pos]?.type === "UNDERSCORE") {
|
|
28
|
+
name += "_";
|
|
29
|
+
consumed++;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return { name, consumed };
|
|
33
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Token } from "../../../lexer";
|
|
2
|
+
import type {
|
|
3
|
+
CodeBlockData,
|
|
4
|
+
Diagnostic,
|
|
5
|
+
Element,
|
|
6
|
+
TocEntry,
|
|
7
|
+
Version,
|
|
8
|
+
WikitextSettings,
|
|
9
|
+
} from "@wdprlib/ast";
|
|
10
|
+
import type { BlockRule, InlineRule } from "./rule";
|
|
11
|
+
import type { ScopeContext } from "./scope";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Parser context passed to rules.
|
|
15
|
+
*
|
|
16
|
+
* Fields are grouped by lifecycle:
|
|
17
|
+
* - Static config (`tokens`, `version`, `trackPositions`, `settings`, rule arrays).
|
|
18
|
+
* - `pos`: per-scope cursor; kept top-level because every rule spread overrides it.
|
|
19
|
+
* - Accumulators (`footnotes`, `tocEntries`, ..., `diagnostics`): shared by array identity.
|
|
20
|
+
* - `scope`: per-scope state with immutable-replace semantics.
|
|
21
|
+
*/
|
|
22
|
+
export interface ParseContext {
|
|
23
|
+
tokens: Token[];
|
|
24
|
+
pos: number;
|
|
25
|
+
version: Version;
|
|
26
|
+
trackPositions: boolean;
|
|
27
|
+
settings: WikitextSettings;
|
|
28
|
+
footnotes: Element[][];
|
|
29
|
+
tocEntries: TocEntry[];
|
|
30
|
+
codeBlocks: CodeBlockData[];
|
|
31
|
+
htmlBlocks: string[];
|
|
32
|
+
bibcites: string[];
|
|
33
|
+
blockRules: BlockRule[];
|
|
34
|
+
blockFallbackRule: BlockRule;
|
|
35
|
+
inlineRules: InlineRule[];
|
|
36
|
+
diagnostics: Diagnostic[];
|
|
37
|
+
scope: ScopeContext;
|
|
38
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Element } from "@wdprlib/ast";
|
|
2
|
+
import type { TokenType } from "../../../lexer";
|
|
3
|
+
import type { ParseContext } from "./parse-context";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Result of a rule attempt.
|
|
7
|
+
*/
|
|
8
|
+
export type RuleResult<T> = { success: true; elements: T[]; consumed: number } | { success: false };
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Block rule interface.
|
|
12
|
+
*/
|
|
13
|
+
export interface BlockRule {
|
|
14
|
+
/** Rule name for debugging. */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Token types that can start this rule. */
|
|
17
|
+
startTokens: TokenType[];
|
|
18
|
+
/** Whether this rule requires line start. */
|
|
19
|
+
requiresLineStart: boolean;
|
|
20
|
+
/** Try to parse this block. */
|
|
21
|
+
parse(ctx: ParseContext): RuleResult<Element>;
|
|
22
|
+
/**
|
|
23
|
+
* Check if tokens at the given position match this rule's start pattern.
|
|
24
|
+
* Used by inline parser to determine behavior before a block boundary.
|
|
25
|
+
*/
|
|
26
|
+
isStartPattern?(ctx: ParseContext, pos: number): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* When true, a single newline before this block becomes a line-break.
|
|
29
|
+
*/
|
|
30
|
+
preservesPrecedingLineBreak?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Inline rule interface.
|
|
35
|
+
*/
|
|
36
|
+
export interface InlineRule {
|
|
37
|
+
/** Rule name for debugging. */
|
|
38
|
+
name: string;
|
|
39
|
+
/** Token types that can start this rule. */
|
|
40
|
+
startTokens: TokenType[];
|
|
41
|
+
/** Try to parse this inline element. */
|
|
42
|
+
parse(ctx: ParseContext): RuleResult<Element>;
|
|
43
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ParseContext } from "./parse-context";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Per-scope state propagated by spread + override semantics.
|
|
5
|
+
*
|
|
6
|
+
* Every field is `readonly` so a rule cannot accidentally mutate the
|
|
7
|
+
* parent scope by writing through a shared reference. Updates must be
|
|
8
|
+
* expressed as a replacement: `ctx.scope = { ...ctx.scope, X: ... }`.
|
|
9
|
+
*/
|
|
10
|
+
export interface ScopeContext {
|
|
11
|
+
/**
|
|
12
|
+
* Close condition for the current block. The paragraph parser calls
|
|
13
|
+
* it to decide when to stop collecting inline content.
|
|
14
|
+
*/
|
|
15
|
+
readonly blockCloseCondition?: (ctx: ParseContext) => boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Block names excluded from paragraph-boundary detection.
|
|
18
|
+
*/
|
|
19
|
+
readonly excludedBlockNames?: ReadonlySet<string>;
|
|
20
|
+
/**
|
|
21
|
+
* Budget for div nesting: tracks how many more nested divs can open.
|
|
22
|
+
*/
|
|
23
|
+
readonly divClosesBudget?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Used by the footnote-block rule to reject duplicate top-level occurrences.
|
|
26
|
+
*
|
|
27
|
+
* Scope is per spread copy of `ParseContext`, not document-global. This keeps
|
|
28
|
+
* the original primitive semantics while avoiding rollback-unsafe shared state.
|
|
29
|
+
*/
|
|
30
|
+
readonly footnoteBlockParsed: boolean;
|
|
31
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { sanitizeUrl as braintreeSanitizeUrl } from "@braintree/sanitize-url";
|
|
2
|
+
|
|
3
|
+
export type AnchorTarget = "new-tab" | "parent" | "top" | "same";
|
|
4
|
+
|
|
5
|
+
export interface AnchorAttributes {
|
|
6
|
+
target: AnchorTarget | null;
|
|
7
|
+
attributes: Record<string, string>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function buildAnchorAttributes(attrs: Record<string, string>): AnchorAttributes {
|
|
11
|
+
const target = parseAnchorTarget(attrs.target);
|
|
12
|
+
const { target: _target, ...cleanAttrs } = attrs;
|
|
13
|
+
|
|
14
|
+
if (cleanAttrs.href) {
|
|
15
|
+
cleanAttrs.href = sanitizeUrl(cleanAttrs.href);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return { target, attributes: cleanAttrs };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function parseAnchorTarget(targetAttr: string | undefined): AnchorTarget | null {
|
|
22
|
+
if (targetAttr === "_blank") return "new-tab";
|
|
23
|
+
if (targetAttr === "_parent") return "parent";
|
|
24
|
+
if (targetAttr === "_top") return "top";
|
|
25
|
+
if (targetAttr === "_self") return "same";
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function sanitizeUrl(url: string): string {
|
|
30
|
+
const normalizedForCheck = stripControlAndWhitespace(url).toLowerCase();
|
|
31
|
+
const dangerousSchemes = ["javascript:", "data:", "vbscript:"];
|
|
32
|
+
for (const scheme of dangerousSchemes) {
|
|
33
|
+
if (normalizedForCheck.startsWith(scheme)) {
|
|
34
|
+
return "#invalid-url";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const sanitized = braintreeSanitizeUrl(url);
|
|
39
|
+
return sanitized === "about:blank" ? "#invalid-url" : url;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const WHITESPACE = /\s/;
|
|
43
|
+
|
|
44
|
+
function stripControlAndWhitespace(value: string): string {
|
|
45
|
+
let result = "";
|
|
46
|
+
for (const char of value) {
|
|
47
|
+
const code = char.charCodeAt(0);
|
|
48
|
+
if (WHITESPACE.test(char) || code <= 0x1f) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
result += char;
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Element } from "@wdprlib/ast";
|
|
2
|
+
import type { ParseContext } from "../../types";
|
|
3
|
+
import { inlineRules } from "../index";
|
|
4
|
+
import { getCandidateInlineRules } from "../utils";
|
|
5
|
+
|
|
6
|
+
export interface AnchorChildResult {
|
|
7
|
+
elements: Element[];
|
|
8
|
+
consumed: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function parseAnchorChild(ctx: ParseContext, pos: number): AnchorChildResult {
|
|
12
|
+
const token = ctx.tokens[pos];
|
|
13
|
+
if (!token) {
|
|
14
|
+
return { elements: [], consumed: 0 };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const inlineCtx: ParseContext = { ...ctx, pos };
|
|
18
|
+
for (const rule of getCandidateInlineRules(inlineRules, token.type)) {
|
|
19
|
+
const result = rule.parse(inlineCtx);
|
|
20
|
+
if (result.success) {
|
|
21
|
+
return { elements: result.elements, consumed: result.consumed };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return { elements: [{ element: "text", data: token.value }], consumed: 1 };
|
|
26
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ParseContext } from "../../types";
|
|
2
|
+
import { isAnchorBlockName, parseAnchorBlockName } from "./syntax";
|
|
3
|
+
|
|
4
|
+
export function tryConsumeAnchorClose(
|
|
5
|
+
ctx: ParseContext,
|
|
6
|
+
pos: number,
|
|
7
|
+
paragraphStrip: boolean,
|
|
8
|
+
): { consumed: number } | null {
|
|
9
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_END_OPEN") {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const closeNameResult = parseAnchorBlockName(ctx, pos + 1);
|
|
14
|
+
if (!closeNameResult || !isAnchorBlockName(closeNameResult.name)) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let consumed = 1 + closeNameResult.consumed;
|
|
19
|
+
let closePos = pos + consumed;
|
|
20
|
+
if (ctx.tokens[closePos]?.type === "BLOCK_CLOSE") {
|
|
21
|
+
closePos++;
|
|
22
|
+
consumed++;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (
|
|
26
|
+
paragraphStrip &&
|
|
27
|
+
ctx.tokens[closePos]?.type === "NEWLINE" &&
|
|
28
|
+
ctx.tokens[closePos + 1]?.type !== "NEWLINE"
|
|
29
|
+
) {
|
|
30
|
+
consumed++;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return { consumed };
|
|
34
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Element } from "@wdprlib/ast";
|
|
2
|
+
import type { ParseContext } from "../../types";
|
|
3
|
+
import { parseAnchorChild } from "./child";
|
|
4
|
+
import { tryConsumeAnchorClose } from "./close";
|
|
5
|
+
import { consumeAnchorNewline } from "./newline";
|
|
6
|
+
import { trimParagraphStripLineBreaks } from "./paragraph-strip";
|
|
7
|
+
|
|
8
|
+
export interface AnchorContentResult {
|
|
9
|
+
children: Element[];
|
|
10
|
+
consumed: number;
|
|
11
|
+
foundClose: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function parseAnchorContent(
|
|
15
|
+
ctx: ParseContext,
|
|
16
|
+
startPos: number,
|
|
17
|
+
paragraphStrip: boolean,
|
|
18
|
+
): AnchorContentResult {
|
|
19
|
+
const children: Element[] = [];
|
|
20
|
+
let pos = startPos;
|
|
21
|
+
let consumed = 0;
|
|
22
|
+
|
|
23
|
+
while (pos < ctx.tokens.length) {
|
|
24
|
+
const token = ctx.tokens[pos];
|
|
25
|
+
if (!token || token.type === "EOF") {
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const closeResult = tryConsumeAnchorClose(ctx, pos, paragraphStrip);
|
|
30
|
+
if (closeResult !== null) {
|
|
31
|
+
trimParagraphStripLineBreaks(children, paragraphStrip);
|
|
32
|
+
return {
|
|
33
|
+
children,
|
|
34
|
+
consumed: consumed + closeResult.consumed,
|
|
35
|
+
foundClose: true,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (token.type === "NEWLINE") {
|
|
40
|
+
const newline = consumeAnchorNewline(ctx, pos, paragraphStrip, children);
|
|
41
|
+
pos += newline.consumed;
|
|
42
|
+
consumed += newline.consumed;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (token.type === "WHITESPACE" && token.lineStart) {
|
|
47
|
+
pos++;
|
|
48
|
+
consumed++;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const child = parseAnchorChild(ctx, pos);
|
|
53
|
+
children.push(...child.elements);
|
|
54
|
+
pos += child.consumed;
|
|
55
|
+
consumed += child.consumed;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { children, consumed, foundClose: false };
|
|
59
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Parses the Wikidot anchor inline block syntax: `[[a]]...[[/a]]`.
|
|
4
|
+
*
|
|
5
|
+
* An anchor wraps inline content in an HTML `<a>` element, allowing
|
|
6
|
+
* href, target, and other HTML attributes to be specified.
|
|
7
|
+
*
|
|
8
|
+
* Wikidot syntax variants:
|
|
9
|
+
* - `[[a href="url"]]text[[/a]]` -- basic anchor with href
|
|
10
|
+
* - `[[a_ href="url"]]text[[/a]]` -- paragraph strip mode (trailing underscore)
|
|
11
|
+
*
|
|
12
|
+
* Paragraph strip mode (`[[a_]]`) suppresses newlines within the anchor
|
|
13
|
+
* body and strips at most one trailing newline after the closing tag
|
|
14
|
+
* (preserving double newlines as paragraph breaks). This prevents
|
|
15
|
+
* unwanted `<br>` elements when consecutive anchor blocks are placed on
|
|
16
|
+
* separate lines.
|
|
17
|
+
*
|
|
18
|
+
* The `target` attribute is extracted and mapped to a semantic enum value
|
|
19
|
+
* (`"new-tab"`, `"parent"`, `"top"`, `"same"`), while the remaining
|
|
20
|
+
* attributes (including `href`) are passed through after URL sanitization.
|
|
21
|
+
*
|
|
22
|
+
* @module
|
|
23
|
+
*/
|
|
24
|
+
import type { Element } from "@wdprlib/ast";
|
|
25
|
+
import type { InlineRule, ParseContext, RuleResult } from "../../types";
|
|
26
|
+
import { currentToken } from "../../types";
|
|
27
|
+
import { buildAnchorAttributes } from "./attributes";
|
|
28
|
+
import { parseAnchorContent } from "./content";
|
|
29
|
+
import { parseAnchorOpen } from "./open";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Inline rule for parsing `[[a]]...[[/a]]` blocks.
|
|
33
|
+
*
|
|
34
|
+
* Triggered by a `BLOCK_OPEN` (`[[`) token. The rule verifies the block name
|
|
35
|
+
* is `a` or `anchor` (optionally with `_` suffix), parses HTML attributes,
|
|
36
|
+
* then recursively parses inline content until the matching closing tag.
|
|
37
|
+
*
|
|
38
|
+
* Produces an `"anchor"` AST element containing the parsed children, a
|
|
39
|
+
* semantic `target` value, and the sanitized attribute map.
|
|
40
|
+
*
|
|
41
|
+
* Edge cases:
|
|
42
|
+
* - If no matching closing tag is found, the rule fails (returns `{ success: false }`),
|
|
43
|
+
* allowing the tokens to fall through to other rules or the text fallback.
|
|
44
|
+
* - In paragraph strip mode, newlines within the body are consumed silently
|
|
45
|
+
* rather than converted to line-break elements. After the closing tag,
|
|
46
|
+
* at most one trailing newline is consumed to prevent a line-break between
|
|
47
|
+
* consecutive `[[a_]]` blocks, but double newlines are preserved as
|
|
48
|
+
* paragraph breaks.
|
|
49
|
+
* - The `href` attribute is sanitized to block `javascript:`, `data:`, and
|
|
50
|
+
* `vbscript:` schemes.
|
|
51
|
+
*/
|
|
52
|
+
export const anchorRule: InlineRule = {
|
|
53
|
+
name: "anchor",
|
|
54
|
+
startTokens: ["BLOCK_OPEN"],
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Attempts to parse an anchor block starting at the current position.
|
|
58
|
+
*
|
|
59
|
+
* @param ctx - Parse context with token stream and current position
|
|
60
|
+
* @returns A successful result with an `"anchor"` element, or `{ success: false }`
|
|
61
|
+
*/
|
|
62
|
+
parse(ctx: ParseContext): RuleResult<Element> {
|
|
63
|
+
const openToken = currentToken(ctx);
|
|
64
|
+
if (openToken.type !== "BLOCK_OPEN") {
|
|
65
|
+
return { success: false };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const openResult = parseAnchorOpen(ctx);
|
|
69
|
+
if (!openResult) {
|
|
70
|
+
return { success: false };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const contentResult = parseAnchorContent(ctx, openResult.bodyStart, openResult.paragraphStrip);
|
|
74
|
+
const consumed = openResult.consumed + contentResult.consumed;
|
|
75
|
+
|
|
76
|
+
if (!contentResult.foundClose) {
|
|
77
|
+
ctx.diagnostics.push({
|
|
78
|
+
severity: "warning",
|
|
79
|
+
code: "unclosed-block",
|
|
80
|
+
message: `Missing closing tag [[/a]] for [[${openResult.name}]]`,
|
|
81
|
+
position: openToken.position,
|
|
82
|
+
});
|
|
83
|
+
return { success: false };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const anchorAttrs = buildAnchorAttributes(openResult.attributes);
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
success: true,
|
|
90
|
+
elements: [
|
|
91
|
+
{
|
|
92
|
+
element: "anchor",
|
|
93
|
+
data: {
|
|
94
|
+
target: anchorAttrs.target,
|
|
95
|
+
attributes: anchorAttrs.attributes,
|
|
96
|
+
elements: contentResult.children,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
consumed,
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Element } from "@wdprlib/ast";
|
|
2
|
+
import type { ParseContext } from "../../types";
|
|
3
|
+
|
|
4
|
+
export interface AnchorNewlineResult {
|
|
5
|
+
consumed: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function consumeAnchorNewline(
|
|
9
|
+
ctx: ParseContext,
|
|
10
|
+
pos: number,
|
|
11
|
+
paragraphStrip: boolean,
|
|
12
|
+
children: Element[],
|
|
13
|
+
): AnchorNewlineResult {
|
|
14
|
+
let consumed = 1;
|
|
15
|
+
let nextPos = pos + 1;
|
|
16
|
+
|
|
17
|
+
if (!paragraphStrip) {
|
|
18
|
+
children.push({ element: "line-break" });
|
|
19
|
+
while (ctx.tokens[nextPos]?.type === "WHITESPACE" && ctx.tokens[nextPos]?.lineStart) {
|
|
20
|
+
nextPos++;
|
|
21
|
+
consumed++;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return { consumed };
|
|
26
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ParseContext } from "../../types";
|
|
2
|
+
import { parseAttributes } from "../../block/utils";
|
|
3
|
+
import { isAnchorBlockName, parseAnchorBlockName } from "./syntax";
|
|
4
|
+
|
|
5
|
+
export interface AnchorOpenResult {
|
|
6
|
+
name: string;
|
|
7
|
+
paragraphStrip: boolean;
|
|
8
|
+
attributes: Record<string, string>;
|
|
9
|
+
bodyStart: number;
|
|
10
|
+
consumed: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function parseAnchorOpen(ctx: ParseContext): AnchorOpenResult | null {
|
|
14
|
+
if (ctx.tokens[ctx.pos]?.type !== "BLOCK_OPEN") {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let pos = ctx.pos + 1;
|
|
19
|
+
let consumed = 1;
|
|
20
|
+
|
|
21
|
+
const nameResult = parseAnchorBlockName(ctx, pos);
|
|
22
|
+
if (!nameResult || !isAnchorBlockName(nameResult.name)) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
pos += nameResult.consumed;
|
|
27
|
+
consumed += nameResult.consumed;
|
|
28
|
+
|
|
29
|
+
const attrResult = parseAttributes(ctx, pos);
|
|
30
|
+
pos += attrResult.consumed;
|
|
31
|
+
consumed += attrResult.consumed;
|
|
32
|
+
|
|
33
|
+
if (ctx.tokens[pos]?.type !== "BLOCK_CLOSE") {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
pos++;
|
|
38
|
+
consumed++;
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
name: nameResult.name,
|
|
42
|
+
paragraphStrip: nameResult.paragraphStrip,
|
|
43
|
+
attributes: attrResult.attrs,
|
|
44
|
+
bodyStart: pos,
|
|
45
|
+
consumed,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Element } from "@wdprlib/ast";
|
|
2
|
+
|
|
3
|
+
export function trimParagraphStripLineBreaks(children: Element[], paragraphStrip: boolean): void {
|
|
4
|
+
if (!paragraphStrip) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
while (children.length > 0 && children[0]?.element === "line-break") {
|
|
9
|
+
children.shift();
|
|
10
|
+
}
|
|
11
|
+
while (children.length > 0 && children[children.length - 1]?.element === "line-break") {
|
|
12
|
+
children.pop();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ParseContext } from "../../types";
|
|
2
|
+
|
|
3
|
+
export interface AnchorBlockName {
|
|
4
|
+
name: string;
|
|
5
|
+
paragraphStrip: boolean;
|
|
6
|
+
consumed: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function parseAnchorBlockName(ctx: ParseContext, startPos: number): AnchorBlockName | null {
|
|
10
|
+
let pos = startPos;
|
|
11
|
+
let consumed = 0;
|
|
12
|
+
|
|
13
|
+
while (ctx.tokens[pos]?.type === "WHITESPACE") {
|
|
14
|
+
pos++;
|
|
15
|
+
consumed++;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const token = ctx.tokens[pos];
|
|
19
|
+
if (!token || (token.type !== "TEXT" && token.type !== "IDENTIFIER")) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let name = token.value.toLowerCase();
|
|
24
|
+
consumed++;
|
|
25
|
+
pos++;
|
|
26
|
+
|
|
27
|
+
let paragraphStrip = false;
|
|
28
|
+
if (ctx.tokens[pos]?.type === "UNDERSCORE") {
|
|
29
|
+
paragraphStrip = true;
|
|
30
|
+
name += "_";
|
|
31
|
+
consumed++;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return { name, paragraphStrip, consumed };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function isAnchorBlockName(name: string): boolean {
|
|
38
|
+
const baseName = name.replace(/_$/, "");
|
|
39
|
+
return baseName === "a" || baseName === "anchor";
|
|
40
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Parses the Wikidot named anchor syntax: `[[# name]]`.
|
|
4
|
+
*
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
import type { Element } from "@wdprlib/ast";
|
|
8
|
+
import type { InlineRule, ParseContext, RuleResult } from "../../types";
|
|
9
|
+
import { currentToken } from "../../types";
|
|
10
|
+
import { parseAnchorNameTarget } from "./syntax";
|
|
11
|
+
|
|
12
|
+
export const anchorNameRule: InlineRule = {
|
|
13
|
+
name: "anchorName",
|
|
14
|
+
startTokens: ["BLOCK_OPEN"],
|
|
15
|
+
|
|
16
|
+
parse(ctx: ParseContext): RuleResult<Element> {
|
|
17
|
+
const openToken = currentToken(ctx);
|
|
18
|
+
if (openToken.type !== "BLOCK_OPEN") {
|
|
19
|
+
return { success: false };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const target = parseAnchorNameTarget(ctx, ctx.pos + 1);
|
|
23
|
+
if (!target) {
|
|
24
|
+
return { success: false };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
success: true,
|
|
29
|
+
elements: [
|
|
30
|
+
{
|
|
31
|
+
element: "anchor-name",
|
|
32
|
+
data: target.name,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
consumed: 1 + target.consumed,
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ParseContext } from "../../types";
|
|
2
|
+
|
|
3
|
+
export function collectAnchorName(
|
|
4
|
+
ctx: ParseContext,
|
|
5
|
+
startPos: number,
|
|
6
|
+
): { name: string; consumed: number } | null {
|
|
7
|
+
let pos = startPos;
|
|
8
|
+
let consumed = 0;
|
|
9
|
+
let name = "";
|
|
10
|
+
|
|
11
|
+
while (pos < ctx.tokens.length) {
|
|
12
|
+
const token = ctx.tokens[pos];
|
|
13
|
+
if (
|
|
14
|
+
!token ||
|
|
15
|
+
token.type === "BLOCK_CLOSE" ||
|
|
16
|
+
token.type === "NEWLINE" ||
|
|
17
|
+
token.type === "EOF"
|
|
18
|
+
) {
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
if (!isValidAnchorNameToken(token.value)) {
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
name += token.value;
|
|
25
|
+
pos++;
|
|
26
|
+
consumed++;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return name ? { name, consumed } : null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isValidAnchorNameToken(value: string): boolean {
|
|
33
|
+
for (const char of value) {
|
|
34
|
+
if (!/^[-_A-Za-z0-9.%]$/.test(char)) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
}
|