@yozora/tokenizer-footnote-definition 2.0.3 → 2.0.5-alpha.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.
@@ -120,20 +120,19 @@ const uniqueName = '@yozora/tokenizer-footnote-definition';
120
120
 
121
121
  class FootnoteDefinitionTokenizer extends coreTokenizer.BaseBlockTokenizer {
122
122
  constructor(props = {}) {
123
- var _a, _b;
124
123
  super({
125
- name: (_a = props.name) !== null && _a !== void 0 ? _a : uniqueName,
126
- priority: (_b = props.priority) !== null && _b !== void 0 ? _b : coreTokenizer.TokenizerPriority.CONTAINING_BLOCK,
124
+ name: props.name ?? uniqueName,
125
+ priority: props.priority ?? coreTokenizer.TokenizerPriority.CONTAINING_BLOCK,
127
126
  });
128
- this.indent = 4;
129
- this.match = match;
130
- this.parse = parse;
131
127
  }
128
+ indent = 4;
129
+ match = match;
130
+ parse = parse;
132
131
  }
133
132
 
134
133
  exports.FootnoteDefinitionTokenizer = FootnoteDefinitionTokenizer;
135
134
  exports.FootnoteDefinitionTokenizerName = uniqueName;
136
- exports["default"] = FootnoteDefinitionTokenizer;
135
+ exports.default = FootnoteDefinitionTokenizer;
137
136
  exports.eatFootnoteLabel = eatFootnoteLabel;
138
137
  exports.footnoteDefinitionMatch = match;
139
138
  exports.footnoteDefinitionParse = parse;
@@ -116,15 +116,14 @@ const uniqueName = '@yozora/tokenizer-footnote-definition';
116
116
 
117
117
  class FootnoteDefinitionTokenizer extends BaseBlockTokenizer {
118
118
  constructor(props = {}) {
119
- var _a, _b;
120
119
  super({
121
- name: (_a = props.name) !== null && _a !== void 0 ? _a : uniqueName,
122
- priority: (_b = props.priority) !== null && _b !== void 0 ? _b : TokenizerPriority.CONTAINING_BLOCK,
120
+ name: props.name ?? uniqueName,
121
+ priority: props.priority ?? TokenizerPriority.CONTAINING_BLOCK,
123
122
  });
124
- this.indent = 4;
125
- this.match = match;
126
- this.parse = parse;
127
123
  }
124
+ indent = 4;
125
+ match = match;
126
+ parse = parse;
128
127
  }
129
128
 
130
129
  export { FootnoteDefinitionTokenizer, uniqueName as FootnoteDefinitionTokenizerName, FootnoteDefinitionTokenizer as default, eatFootnoteLabel, match as footnoteDefinitionMatch, parse as footnoteDefinitionParse };
@@ -20,8 +20,8 @@ import { FootnoteDefinitionType, FootnoteDefinition } from '@yozora/ast';
20
20
  */
21
21
  declare function eatFootnoteLabel(nodePoints: ReadonlyArray<INodePoint>, firstNonWhitespaceIndex: number, endIndex: number): number;
22
22
 
23
- declare type T = FootnoteDefinitionType;
24
- declare type INode = FootnoteDefinition;
23
+ type T = FootnoteDefinitionType;
24
+ type INode = FootnoteDefinition;
25
25
  declare const uniqueName = "@yozora/tokenizer-footnote-definition";
26
26
  interface IToken extends IPartialYastBlockToken<T> {
27
27
  /**
@@ -46,7 +46,7 @@ interface IToken extends IPartialYastBlockToken<T> {
46
46
  interface IThis extends ITokenizer {
47
47
  indent: number;
48
48
  }
49
- declare type ITokenizerProps = Partial<IBaseBlockTokenizerProps>;
49
+ type ITokenizerProps = Partial<IBaseBlockTokenizerProps>;
50
50
 
51
51
  /**
52
52
  * A footnote reference definition consists of a footnote label, indented up
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yozora/tokenizer-footnote-definition",
3
- "version": "2.0.3",
3
+ "version": "2.0.5-alpha.0",
4
4
  "author": {
5
5
  "name": "guanghechen",
6
6
  "url": "https://github.com/guanghechen/"
@@ -11,33 +11,37 @@
11
11
  "directory": "tokenizers/footnote-definition"
12
12
  },
13
13
  "homepage": "https://github.com/yozorajs/yozora/tree/release-2.x.x/tokenizers/footnote-definition",
14
- "main": "lib/cjs/index.js",
15
- "module": "lib/esm/index.js",
16
- "types": "lib/types/index.d.ts",
17
- "source": "src/index.ts",
14
+ "type": "module",
15
+ "exports": {
16
+ "types": "./lib/types/index.d.ts",
17
+ "import": "./lib/esm/index.mjs",
18
+ "require": "./lib/cjs/index.cjs"
19
+ },
20
+ "source": "./src/index.ts",
21
+ "types": "./lib/types/index.d.ts",
22
+ "main": "./lib/cjs/index.cjs",
23
+ "module": "./lib/esm/index.mjs",
18
24
  "license": "MIT",
19
25
  "engines": {
20
26
  "node": ">= 16.0.0"
21
27
  },
22
28
  "files": [
23
29
  "lib/",
24
- "!lib/**/*.js.map",
25
- "!lib/**/*.d.ts.map",
30
+ "src/",
26
31
  "package.json",
27
32
  "CHANGELOG.md",
28
33
  "LICENSE",
29
34
  "README.md"
30
35
  ],
31
36
  "scripts": {
32
- "build": "cross-env NODE_ENV=production rollup -c ../../rollup.config.js",
33
- "prebuild": "rimraf lib/",
37
+ "build": "rimraf lib/ && cross-env NODE_ENV=production rollup -c ../../rollup.config.mjs",
34
38
  "prepublishOnly": "cross-env ROLLUP_SHOULD_SOURCEMAP=false yarn build",
35
- "test": "cross-env TS_NODE_FILES=true jest --config ../../jest.config.js --rootDir ."
39
+ "test": "cross-env TS_NODE_FILES=true NODE_OPTIONS=--experimental-vm-modules jest --config ../../jest.config.mjs --rootDir ."
36
40
  },
37
41
  "dependencies": {
38
- "@yozora/ast": "^2.0.3",
39
- "@yozora/character": "^2.0.3",
40
- "@yozora/core-tokenizer": "^2.0.3"
42
+ "@yozora/ast": "^2.0.5-alpha.0",
43
+ "@yozora/character": "^2.0.5-alpha.0",
44
+ "@yozora/core-tokenizer": "^2.0.5-alpha.0"
41
45
  },
42
- "gitHead": "8cc8f95cfebc8d752bc3272cdd24965f540c130b"
46
+ "gitHead": "8bf941fe4ef82947165b0f3cc123cd493665e13b"
43
47
  }
package/src/index.ts ADDED
@@ -0,0 +1,10 @@
1
+ export * from './util'
2
+ export { match as footnoteDefinitionMatch } from './match'
3
+ export { parse as footnoteDefinitionParse } from './parse'
4
+ export { FootnoteDefinitionTokenizer, FootnoteDefinitionTokenizer as default } from './tokenizer'
5
+ export { uniqueName as FootnoteDefinitionTokenizerName } from './types'
6
+ export type {
7
+ IThis as IFootnoteDefinitionHookContext,
8
+ IToken as IFootnoteDefinitionToken,
9
+ ITokenizerProps as IFootnoteDefinitionTokenizerProps,
10
+ } from './types'
package/src/match.ts ADDED
@@ -0,0 +1,115 @@
1
+ import { FootnoteDefinitionType } from '@yozora/ast'
2
+ import { AsciiCodePoint, calcStringFromNodePoints } from '@yozora/character'
3
+ import type {
4
+ IMatchBlockHookCreator,
5
+ IPhrasingContentLine,
6
+ IResultOfEatContinuationText,
7
+ IResultOfEatOpener,
8
+ IResultOfOnClose,
9
+ } from '@yozora/core-tokenizer'
10
+ import { calcEndPoint, calcStartPoint, resolveLabelToIdentifier } from '@yozora/core-tokenizer'
11
+ import type { IThis, IToken, T } from './types'
12
+ import { eatFootnoteLabel } from './util'
13
+
14
+ /**
15
+ * A footnote reference definition consists of a footnote label, indented up
16
+ * to three spaces, followed by a colon (:), optional whitespace (including up
17
+ * to one line ending), a footnote contents consisted by paragraph-like strings.
18
+ *
19
+ * Unlike the link label, the footnote label should be on the same line and it
20
+ * begins with a left bracket ([) followed by a caret (^), and ends with the
21
+ * first right bracket (]) that is not backslash-escaped. Between the caret of
22
+ * right bracket, there must be at least one non-whitespace character.
23
+ * Unescaped square bracket characters are not allowed inside the opening creat
24
+ * and closing square bracket of footnote labels. A footnote label can have at
25
+ * most 999 characters inside the caret and right bracket.
26
+ *
27
+ * @see https://github.github.com/gfm/#link-label
28
+ * @see https://github.github.com/gfm/#link-reference-definition
29
+ * @see https://github.com/syntax-tree/mdast-util-footnote
30
+ * @see https://github.com/remarkjs/remark-footnotes
31
+ * @see https://www.markdownguide.org/extended-syntax/#footnotes
32
+ */
33
+ export const match: IMatchBlockHookCreator<T, IToken, IThis> = function (api) {
34
+ const { indent } = this
35
+ return {
36
+ isContainingBlock: true,
37
+ eatOpener,
38
+ eatContinuationText,
39
+ onClose,
40
+ }
41
+
42
+ function eatOpener(line: Readonly<IPhrasingContentLine>): IResultOfEatOpener<T, IToken> {
43
+ if (line.countOfPrecedeSpaces >= 4) return null
44
+
45
+ const { nodePoints, startIndex, firstNonWhitespaceIndex, endIndex } = line
46
+ const nextIndex = eatFootnoteLabel(nodePoints, firstNonWhitespaceIndex, endIndex)
47
+
48
+ // Try to match the following colon (:).
49
+ if (
50
+ nextIndex < 0 ||
51
+ nextIndex >= endIndex ||
52
+ nodePoints[nextIndex].codePoint !== AsciiCodePoint.COLON
53
+ ) {
54
+ return null
55
+ }
56
+
57
+ const token: IToken = {
58
+ nodeType: FootnoteDefinitionType,
59
+ position: {
60
+ start: calcStartPoint(nodePoints, startIndex),
61
+ end: calcEndPoint(nodePoints, nextIndex),
62
+ },
63
+ label: {
64
+ nodePoints,
65
+ startIndex: firstNonWhitespaceIndex,
66
+ endIndex: nextIndex,
67
+ },
68
+ children: [],
69
+ }
70
+ return { token, nextIndex: nextIndex + 1 }
71
+ }
72
+
73
+ function eatContinuationText(line: Readonly<IPhrasingContentLine>): IResultOfEatContinuationText {
74
+ const { startIndex, endIndex, firstNonWhitespaceIndex, countOfPrecedeSpaces } = line
75
+
76
+ // Blank line is allowed
77
+ if (firstNonWhitespaceIndex >= endIndex) {
78
+ return {
79
+ status: 'opening',
80
+ nextIndex: Math.min(endIndex - 1, startIndex + indent),
81
+ }
82
+ }
83
+
84
+ // Indent of a non-blank line is required.
85
+ if (countOfPrecedeSpaces >= indent) {
86
+ return { status: 'opening', nextIndex: startIndex + indent }
87
+ }
88
+
89
+ return { status: 'notMatched' }
90
+ }
91
+
92
+ function onClose(token: IToken): IResultOfOnClose {
93
+ /**
94
+ * Labels are trimmed and case-insensitive
95
+ * @see https://github.github.com/gfm/#example-174
96
+ * @see https://github.github.com/gfm/#example-175
97
+ */
98
+ const label = calcStringFromNodePoints(
99
+ token.label.nodePoints,
100
+ token.label.startIndex + 2,
101
+ token.label.endIndex - 1,
102
+ )
103
+ const identifier = resolveLabelToIdentifier(label)
104
+
105
+ // Register definition identifier.
106
+ api.registerFootnoteDefinitionIdentifier(identifier)
107
+
108
+ // Cache label and identifier for performance.
109
+
110
+ // eslint-disable-next-line no-param-reassign
111
+ token._label = label
112
+ // eslint-disable-next-line no-param-reassign
113
+ token._identifier = identifier
114
+ }
115
+ }
package/src/parse.ts ADDED
@@ -0,0 +1,31 @@
1
+ import type { Node } from '@yozora/ast'
2
+ import { FootnoteDefinitionType } from '@yozora/ast'
3
+ import type { IParseBlockHookCreator } from '@yozora/core-tokenizer'
4
+ import type { INode, IThis, IToken, T } from './types'
5
+
6
+ export const parse: IParseBlockHookCreator<T, IToken, INode, IThis> = function (api) {
7
+ return {
8
+ parse: tokens =>
9
+ tokens.map(token => {
10
+ const label: string = token._label!
11
+ const identifier: string = token._identifier!
12
+
13
+ const children: Node[] = api.parseBlockTokens(token.children)
14
+ const node: INode = api.shouldReservePosition
15
+ ? {
16
+ type: FootnoteDefinitionType,
17
+ position: token.position,
18
+ identifier,
19
+ label,
20
+ children,
21
+ }
22
+ : {
23
+ type: FootnoteDefinitionType,
24
+ identifier,
25
+ label,
26
+ children,
27
+ }
28
+ return node
29
+ }),
30
+ }
31
+ }
@@ -0,0 +1,37 @@
1
+ import type {
2
+ IBlockTokenizer,
3
+ IMatchBlockHookCreator,
4
+ IParseBlockHookCreator,
5
+ } from '@yozora/core-tokenizer'
6
+ import { BaseBlockTokenizer, TokenizerPriority } from '@yozora/core-tokenizer'
7
+ import { match } from './match'
8
+ import { parse } from './parse'
9
+ import type { INode, IThis, IToken, ITokenizerProps, T } from './types'
10
+ import { uniqueName } from './types'
11
+
12
+ /**
13
+ * Lexical Analyzer for FootnoteDefinition.
14
+ * @see https://github.github.com/gfm/#link-label
15
+ * @see https://github.github.com/gfm/#link-reference-definition
16
+ * @see https://github.com/syntax-tree/mdast-util-footnote
17
+ * @see https://github.com/remarkjs/remark-footnotes
18
+ * @see https://www.markdownguide.org/extended-syntax/#footnotes
19
+ */
20
+ export class FootnoteDefinitionTokenizer
21
+ extends BaseBlockTokenizer<T, IToken, INode, IThis>
22
+ implements IBlockTokenizer<T, IToken, INode, IThis>
23
+ {
24
+ /* istanbul ignore next */
25
+ constructor(props: ITokenizerProps = {}) {
26
+ super({
27
+ name: props.name ?? uniqueName,
28
+ priority: props.priority ?? TokenizerPriority.CONTAINING_BLOCK,
29
+ })
30
+ }
31
+
32
+ public readonly indent = 4
33
+
34
+ public override readonly match: IMatchBlockHookCreator<T, IToken, IThis> = match
35
+
36
+ public override readonly parse: IParseBlockHookCreator<T, IToken, INode, IThis> = parse
37
+ }
package/src/types.ts ADDED
@@ -0,0 +1,37 @@
1
+ import type { FootnoteDefinition, FootnoteDefinitionType } from '@yozora/ast'
2
+ import type { INodeInterval, INodePoint } from '@yozora/character'
3
+ import type {
4
+ IBaseBlockTokenizerProps,
5
+ IPartialYastBlockToken,
6
+ ITokenizer,
7
+ IYastBlockToken,
8
+ } from '@yozora/core-tokenizer'
9
+
10
+ export type T = FootnoteDefinitionType
11
+ export type INode = FootnoteDefinition
12
+ export const uniqueName = '@yozora/tokenizer-footnote-definition'
13
+
14
+ export interface IToken extends IPartialYastBlockToken<T> {
15
+ /**
16
+ * Footnote label
17
+ */
18
+ label: INodeInterval & { nodePoints: ReadonlyArray<INodePoint> }
19
+ /**
20
+ *
21
+ */
22
+ children: IYastBlockToken[]
23
+ /**
24
+ * Resolved definition label.
25
+ */
26
+ _label?: string
27
+ /**
28
+ * Resolved definition identifier.
29
+ */
30
+ _identifier?: string
31
+ }
32
+
33
+ export interface IThis extends ITokenizer {
34
+ indent: number
35
+ }
36
+
37
+ export type ITokenizerProps = Partial<IBaseBlockTokenizerProps>
package/src/util.ts ADDED
@@ -0,0 +1,58 @@
1
+ import type { INodePoint } from '@yozora/character'
2
+ import { AsciiCodePoint, VirtualCodePoint, isWhitespaceCharacter } from '@yozora/character'
3
+
4
+ /**
5
+ * Try to match a footnote label.
6
+ *
7
+ * Unlike the link label, the footnote label should be on the same line and it
8
+ * begins with a left bracket ([) followed by a caret (^), and ends with the
9
+ * first right bracket (]) that is not backslash-escaped. Between the caret of
10
+ * right bracket, there must be at least one non-whitespace character.
11
+ * Unescaped square bracket characters are not allowed inside the opening creat
12
+ * and closing square bracket of footnote labels. A footnote label can have at
13
+ * most 999 characters inside the caret and right bracket.
14
+ *
15
+ * @param nodePoints
16
+ * @param firstNonWhitespaceIndex
17
+ * @param endIndex
18
+ * @see https://github.github.com/gfm/#link-label
19
+ */
20
+ export function eatFootnoteLabel(
21
+ nodePoints: ReadonlyArray<INodePoint>,
22
+ firstNonWhitespaceIndex: number,
23
+ endIndex: number,
24
+ ): number {
25
+ let i = firstNonWhitespaceIndex
26
+
27
+ // Try to match an opening delimiter of a footnote label.
28
+ if (
29
+ i + 1 >= endIndex ||
30
+ nodePoints[i].codePoint !== AsciiCodePoint.OPEN_BRACKET ||
31
+ nodePoints[i + 1].codePoint !== AsciiCodePoint.CARET
32
+ ) {
33
+ return -1
34
+ }
35
+
36
+ let isEmpty = true
37
+ const lastIndex = Math.min(endIndex, i + 1 + 1000)
38
+ for (i += 2; i < lastIndex; ++i) {
39
+ const c = nodePoints[i].codePoint
40
+ switch (c) {
41
+ case AsciiCodePoint.BACKSLASH:
42
+ i += 1
43
+ break
44
+ case AsciiCodePoint.OPEN_BRACKET:
45
+ return -1
46
+ case AsciiCodePoint.CLOSE_BRACKET:
47
+ return isEmpty ? -1 : i + 1
48
+ case VirtualCodePoint.LINE_END:
49
+ return -1
50
+ default:
51
+ if (isEmpty && !isWhitespaceCharacter(c)) {
52
+ isEmpty = false
53
+ }
54
+ }
55
+ }
56
+
57
+ return -1
58
+ }