@incremark/core 0.2.2 ā 0.2.4
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/detector/index.d.ts +1 -1
- package/dist/detector/index.js +59 -2
- package/dist/detector/index.js.map +1 -1
- package/dist/{index-3rgnFbip.d.ts ā index-zDgyJFpf.d.ts} +8 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +83 -6
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
- package/src/__tests__/footnote.test.ts +0 -214
- package/src/benchmark/index.ts +0 -443
- package/src/benchmark/run.ts +0 -93
- package/src/detector/index.test.ts +0 -150
- package/src/detector/index.ts +0 -330
- package/src/extensions/html-extension/index.test.ts +0 -409
- package/src/extensions/html-extension/index.ts +0 -792
- package/src/extensions/micromark-gfm-footnote-incremental.ts +0 -275
- package/src/extensions/micromark-reference-extension.ts +0 -724
- package/src/index.ts +0 -128
- package/src/parser/IncremarkParser.comprehensive.test.ts +0 -418
- package/src/parser/IncremarkParser.footnote.test.ts +0 -334
- package/src/parser/IncremarkParser.robustness.test.ts +0 -428
- package/src/parser/IncremarkParser.test.ts +0 -110
- package/src/parser/IncremarkParser.ts +0 -839
- package/src/parser/index.ts +0 -2
- package/src/transformer/BlockTransformer.ts +0 -640
- package/src/transformer/index.ts +0 -36
- package/src/transformer/plugins.ts +0 -113
- package/src/transformer/types.ts +0 -115
- package/src/transformer/utils.ts +0 -364
- package/src/types/index.ts +0 -183
- package/src/utils/index.ts +0 -53
package/src/benchmark/run.ts
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { runBenchmark } from './index'
|
|
2
|
-
|
|
3
|
-
console.log('')
|
|
4
|
-
console.log('š¬ Running Incremark Benchmark Suite')
|
|
5
|
-
console.log('')
|
|
6
|
-
|
|
7
|
-
// äøåę攣éæåŗ¦ēęµčÆ
|
|
8
|
-
const documentSizes = [
|
|
9
|
-
{ name: 'Short (~1KB)', length: 1000 },
|
|
10
|
-
{ name: 'Medium (~5KB)', length: 5000 },
|
|
11
|
-
{ name: 'Long (~10KB)', length: 10000 },
|
|
12
|
-
{ name: 'Very Long (~20KB)', length: 20000 },
|
|
13
|
-
]
|
|
14
|
-
|
|
15
|
-
const allResults: Array<{
|
|
16
|
-
docSize: string
|
|
17
|
-
docLength: number
|
|
18
|
-
chunkSize: number
|
|
19
|
-
timeSaved: number
|
|
20
|
-
charsSaved: number
|
|
21
|
-
speedup: number
|
|
22
|
-
}> = []
|
|
23
|
-
|
|
24
|
-
for (const doc of documentSizes) {
|
|
25
|
-
console.log(`\n${'='.repeat(60)}`)
|
|
26
|
-
console.log(`š Document Size: ${doc.name} (${doc.length} chars)`)
|
|
27
|
-
console.log('='.repeat(60))
|
|
28
|
-
|
|
29
|
-
// ęµčÆäøå chunk 大å°
|
|
30
|
-
for (const chunkSize of [10, 50]) {
|
|
31
|
-
console.log(`\nš¦ Chunk size: ${chunkSize} chars\n`)
|
|
32
|
-
const result = runBenchmark({
|
|
33
|
-
chunkSize,
|
|
34
|
-
iterations: 20,
|
|
35
|
-
markdownLength: doc.length
|
|
36
|
-
})
|
|
37
|
-
allResults.push({
|
|
38
|
-
docSize: doc.name,
|
|
39
|
-
docLength: doc.length,
|
|
40
|
-
chunkSize,
|
|
41
|
-
timeSaved: result.timeSaved,
|
|
42
|
-
charsSaved: result.charsSaved,
|
|
43
|
-
speedup: result.speedup
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// ę±ę»ę„å
|
|
49
|
-
console.log('\n')
|
|
50
|
-
console.log('='.repeat(80))
|
|
51
|
-
console.log('š Complete Benchmark Summary')
|
|
52
|
-
console.log('='.repeat(80))
|
|
53
|
-
console.log('')
|
|
54
|
-
console.log('| Document Size | Chunk | Time Saved | Chars Saved | Speedup |')
|
|
55
|
-
console.log('|------------------|-------|------------|-------------|---------|')
|
|
56
|
-
for (const r of allResults) {
|
|
57
|
-
console.log(`| ${r.docSize.padEnd(16)} | ${r.chunkSize.toString().padEnd(5)} | ${r.timeSaved.toFixed(1).padStart(9)}% | ${r.charsSaved.toFixed(1).padStart(10)}% | ${r.speedup.toFixed(2).padStart(6)}x |`)
|
|
58
|
-
}
|
|
59
|
-
console.log('')
|
|
60
|
-
|
|
61
|
-
// č®”ē®å¹³åå¼
|
|
62
|
-
const avgTimeSaved = allResults.reduce((sum, r) => sum + r.timeSaved, 0) / allResults.length
|
|
63
|
-
const avgCharsSaved = allResults.reduce((sum, r) => sum + r.charsSaved, 0) / allResults.length
|
|
64
|
-
const avgSpeedup = allResults.reduce((sum, r) => sum + r.speedup, 0) / allResults.length
|
|
65
|
-
|
|
66
|
-
// ęę攣大å°åē»č®”ē®
|
|
67
|
-
const byDocSize = new Map<string, typeof allResults>()
|
|
68
|
-
for (const r of allResults) {
|
|
69
|
-
if (!byDocSize.has(r.docSize)) {
|
|
70
|
-
byDocSize.set(r.docSize, [])
|
|
71
|
-
}
|
|
72
|
-
byDocSize.get(r.docSize)!.push(r)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
console.log('-'.repeat(80))
|
|
76
|
-
console.log('')
|
|
77
|
-
console.log('š Average by Document Size:')
|
|
78
|
-
console.log('')
|
|
79
|
-
for (const [size, results] of byDocSize) {
|
|
80
|
-
const avgSpeed = results.reduce((sum, r) => sum + r.speedup, 0) / results.length
|
|
81
|
-
const avgTime = results.reduce((sum, r) => sum + r.timeSaved, 0) / results.length
|
|
82
|
-
console.log(` ${size}: ${avgSpeed.toFixed(2)}x faster, ${avgTime.toFixed(1)}% time saved`)
|
|
83
|
-
}
|
|
84
|
-
console.log('')
|
|
85
|
-
|
|
86
|
-
console.log('-'.repeat(80))
|
|
87
|
-
console.log('')
|
|
88
|
-
console.log(`šÆ Overall Average:`)
|
|
89
|
-
console.log(` Time Saved: ${avgTimeSaved.toFixed(1)}%`)
|
|
90
|
-
console.log(` Chars Saved: ${avgCharsSaved.toFixed(1)}%`)
|
|
91
|
-
console.log(` Speedup: ${avgSpeedup.toFixed(2)}x`)
|
|
92
|
-
console.log('')
|
|
93
|
-
console.log('='.repeat(80))
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import {
|
|
3
|
-
detectFenceStart,
|
|
4
|
-
detectFenceEnd,
|
|
5
|
-
isEmptyLine,
|
|
6
|
-
isHeading,
|
|
7
|
-
isThematicBreak,
|
|
8
|
-
isListItemStart,
|
|
9
|
-
isBlockquoteStart,
|
|
10
|
-
detectContainer,
|
|
11
|
-
createInitialContext
|
|
12
|
-
} from './index'
|
|
13
|
-
|
|
14
|
-
describe('åę£ęµåØ', () => {
|
|
15
|
-
describe('detectFenceStart', () => {
|
|
16
|
-
it('ę£ęµåå¼å· fence', () => {
|
|
17
|
-
const result = detectFenceStart('```js')
|
|
18
|
-
expect(result).toEqual({ char: '`', length: 3 })
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it('ę£ęµę³¢ęµŖå· fence', () => {
|
|
22
|
-
const result = detectFenceStart('~~~python')
|
|
23
|
-
expect(result).toEqual({ char: '~', length: 3 })
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
it('ę£ęµę“éæē fence', () => {
|
|
27
|
-
const result = detectFenceStart('`````')
|
|
28
|
-
expect(result).toEqual({ char: '`', length: 5 })
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('é fence čæå null', () => {
|
|
32
|
-
expect(detectFenceStart('ę®éęę¬')).toBeNull()
|
|
33
|
-
expect(detectFenceStart('``äøå¤éæ')).toBeNull()
|
|
34
|
-
})
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
describe('detectFenceEnd', () => {
|
|
38
|
-
it('å¹é
ēøåéæåŗ¦', () => {
|
|
39
|
-
const context = { ...createInitialContext(), inFencedCode: true, fenceChar: '`', fenceLength: 3 }
|
|
40
|
-
expect(detectFenceEnd('```', context)).toBe(true)
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('å¹é
ę“éæēē»ę', () => {
|
|
44
|
-
const context = { ...createInitialContext(), inFencedCode: true, fenceChar: '`', fenceLength: 3 }
|
|
45
|
-
expect(detectFenceEnd('`````', context)).toBe(true)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('äøå¹é
ę“ēē', () => {
|
|
49
|
-
const context = { ...createInitialContext(), inFencedCode: true, fenceChar: '`', fenceLength: 5 }
|
|
50
|
-
expect(detectFenceEnd('```', context)).toBe(false)
|
|
51
|
-
})
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
describe('isEmptyLine', () => {
|
|
55
|
-
it('空č”', () => {
|
|
56
|
-
expect(isEmptyLine('')).toBe(true)
|
|
57
|
-
expect(isEmptyLine(' ')).toBe(true)
|
|
58
|
-
expect(isEmptyLine('\t')).toBe(true)
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('é空č”', () => {
|
|
62
|
-
expect(isEmptyLine('å
容')).toBe(false)
|
|
63
|
-
expect(isEmptyLine(' a ')).toBe(false)
|
|
64
|
-
})
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
describe('isHeading', () => {
|
|
68
|
-
it('ęęę é¢', () => {
|
|
69
|
-
expect(isHeading('# H1')).toBe(true)
|
|
70
|
-
expect(isHeading('## H2')).toBe(true)
|
|
71
|
-
expect(isHeading('###### H6')).toBe(true)
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
it('ę ęę é¢', () => {
|
|
75
|
-
expect(isHeading('####### H7')).toBe(false) // č¶
čæ 6 ēŗ§
|
|
76
|
-
expect(isHeading('#ę²”ęē©ŗę ¼')).toBe(false)
|
|
77
|
-
expect(isHeading('ę®éęę¬')).toBe(false)
|
|
78
|
-
})
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
describe('isThematicBreak', () => {
|
|
82
|
-
it('ęę氓平线', () => {
|
|
83
|
-
expect(isThematicBreak('---')).toBe(true)
|
|
84
|
-
expect(isThematicBreak('***')).toBe(true)
|
|
85
|
-
expect(isThematicBreak('___')).toBe(true)
|
|
86
|
-
expect(isThematicBreak('-----')).toBe(true)
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('ę ę氓平线', () => {
|
|
90
|
-
expect(isThematicBreak('--')).toBe(false)
|
|
91
|
-
expect(isThematicBreak('- - -')).toBe(false) // ęē©ŗę ¼
|
|
92
|
-
})
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
describe('isListItemStart', () => {
|
|
96
|
-
it('ę åŗå蔨', () => {
|
|
97
|
-
expect(isListItemStart('- item')).toEqual({ ordered: false, indent: 0 })
|
|
98
|
-
expect(isListItemStart(' * item')).toEqual({ ordered: false, indent: 2 })
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
it('ęåŗå蔨', () => {
|
|
102
|
-
expect(isListItemStart('1. item')).toEqual({ ordered: true, indent: 0 })
|
|
103
|
-
expect(isListItemStart(' 99. item')).toEqual({ ordered: true, indent: 2 })
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
it('éå蔨', () => {
|
|
107
|
-
expect(isListItemStart('ę®éęę¬')).toBeNull()
|
|
108
|
-
})
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
describe('isBlockquoteStart', () => {
|
|
112
|
-
it('ęęå¼ēØ', () => {
|
|
113
|
-
expect(isBlockquoteStart('> quote')).toBe(true)
|
|
114
|
-
expect(isBlockquoteStart(' > quote')).toBe(true)
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
it('ę ęå¼ēØ', () => {
|
|
118
|
-
expect(isBlockquoteStart(' > 太å¤ē¼©čæ')).toBe(false)
|
|
119
|
-
})
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
describe('detectContainer', () => {
|
|
123
|
-
it('ę£ęµå®¹åØå¼å§', () => {
|
|
124
|
-
const result = detectContainer('::: warning')
|
|
125
|
-
expect(result).toEqual({ name: 'warning', markerLength: 3, isEnd: false })
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
it('ę£ęµå®¹åØē»ę', () => {
|
|
129
|
-
const result = detectContainer(':::')
|
|
130
|
-
expect(result).toEqual({ name: '', markerLength: 3, isEnd: true })
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
it('ę£ęµę“éæēę č®°', () => {
|
|
134
|
-
const result = detectContainer('::::: outer')
|
|
135
|
-
expect(result).toEqual({ name: 'outer', markerLength: 5, isEnd: false })
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
it('åē§°ē½åå', () => {
|
|
139
|
-
const config = { allowedNames: ['warning', 'info'] }
|
|
140
|
-
expect(detectContainer('::: warning', config)).not.toBeNull()
|
|
141
|
-
expect(detectContainer('::: danger', config)).toBeNull()
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
it('é容åØčÆę³', () => {
|
|
145
|
-
expect(detectContainer('ę®éęę¬')).toBeNull()
|
|
146
|
-
expect(detectContainer(':: 太ē')).toBeNull()
|
|
147
|
-
})
|
|
148
|
-
})
|
|
149
|
-
})
|
|
150
|
-
|
package/src/detector/index.ts
DELETED
|
@@ -1,330 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* åē±»åę£ęµäøč¾¹ēå¤ę
|
|
3
|
-
*
|
|
4
|
-
* Markdown åēŗ§å
ē“ ēčÆå«č§å
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { BlockContext, ContainerConfig, ContainerMatch } from '../types'
|
|
8
|
-
|
|
9
|
-
// ============ é¢ē¼čÆę£å蔨达å¼ļ¼ę§č½ä¼åļ¼ ============
|
|
10
|
-
|
|
11
|
-
const RE_FENCE_START = /^(\s*)((`{3,})|(~{3,}))/
|
|
12
|
-
const RE_EMPTY_LINE = /^\s*$/
|
|
13
|
-
const RE_HEADING = /^#{1,6}\s/
|
|
14
|
-
const RE_THEMATIC_BREAK = /^(\*{3,}|-{3,}|_{3,})\s*$/
|
|
15
|
-
const RE_UNORDERED_LIST = /^(\s*)([-*+])\s/
|
|
16
|
-
const RE_ORDERED_LIST = /^(\s*)(\d{1,9})[.)]\s/
|
|
17
|
-
const RE_BLOCKQUOTE = /^\s{0,3}>/
|
|
18
|
-
const RE_HTML_BLOCK_1 = /^\s{0,3}<(script|pre|style|textarea|!--|!DOCTYPE|\?|!\[CDATA\[)/i
|
|
19
|
-
const RE_HTML_BLOCK_2 = /^\s{0,3}<\/?[a-zA-Z][a-zA-Z0-9-]*(\s|>|$)/
|
|
20
|
-
const RE_TABLE_DELIMITER = /^\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)*\|?$/
|
|
21
|
-
const RE_ESCAPE_SPECIAL = /[.*+?^${}()|[\]\\]/g
|
|
22
|
-
const RE_FOOTNOTE_DEFINITION = /^\[\^[^\]]+\]:\s/
|
|
23
|
-
const RE_FOOTNOTE_CONTINUATION = /^(?: |\t)/
|
|
24
|
-
|
|
25
|
-
/** fence ē»ę樔å¼ē¼å */
|
|
26
|
-
const fenceEndPatternCache = new Map<string, RegExp>()
|
|
27
|
-
|
|
28
|
-
/** 容åØęØ”å¼ē¼å */
|
|
29
|
-
const containerPatternCache = new Map<string, RegExp>()
|
|
30
|
-
|
|
31
|
-
// ============ 代ē åę£ęµ ============
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* ę£ęµč”ęÆå¦ęÆä»£ē å fence å¼å§
|
|
35
|
-
*/
|
|
36
|
-
export function detectFenceStart(line: string): { char: string; length: number } | null {
|
|
37
|
-
const match = line.match(RE_FENCE_START)
|
|
38
|
-
if (match) {
|
|
39
|
-
const fence = match[2]
|
|
40
|
-
const char = fence[0]
|
|
41
|
-
return { char, length: fence.length }
|
|
42
|
-
}
|
|
43
|
-
return null
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* ę£ęµč”ęÆå¦ęÆä»£ē å fence ē»ę
|
|
48
|
-
*/
|
|
49
|
-
export function detectFenceEnd(line: string, context: BlockContext): boolean {
|
|
50
|
-
if (!context.inFencedCode || !context.fenceChar || !context.fenceLength) {
|
|
51
|
-
return false
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// 使ēØē¼åēę£å蔨达å¼
|
|
55
|
-
const cacheKey = `${context.fenceChar}-${context.fenceLength}`
|
|
56
|
-
let pattern = fenceEndPatternCache.get(cacheKey)
|
|
57
|
-
if (!pattern) {
|
|
58
|
-
pattern = new RegExp(`^\\s{0,3}${context.fenceChar}{${context.fenceLength},}\\s*$`)
|
|
59
|
-
fenceEndPatternCache.set(cacheKey, pattern)
|
|
60
|
-
}
|
|
61
|
-
return pattern.test(line)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// ============ č”ē±»åę£ęµ ============
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* ę£ęµęÆå¦ęÆē©ŗč”ęä»
å
å«ē©ŗē½å符
|
|
68
|
-
*/
|
|
69
|
-
export function isEmptyLine(line: string): boolean {
|
|
70
|
-
return RE_EMPTY_LINE.test(line)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* ę£ęµęÆå¦ęÆę é¢č”
|
|
75
|
-
*/
|
|
76
|
-
export function isHeading(line: string): boolean {
|
|
77
|
-
return RE_HEADING.test(line)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* ę£ęµęÆå¦ęÆ thematic breakļ¼ę°“平线ļ¼
|
|
82
|
-
*/
|
|
83
|
-
export function isThematicBreak(line: string): boolean {
|
|
84
|
-
return RE_THEMATIC_BREAK.test(line.trim())
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* ę£ęµęÆå¦ęÆå蔨锹å¼å§
|
|
89
|
-
*/
|
|
90
|
-
export function isListItemStart(line: string): { ordered: boolean; indent: number } | null {
|
|
91
|
-
// ę åŗå蔨: - * +
|
|
92
|
-
const unordered = line.match(RE_UNORDERED_LIST)
|
|
93
|
-
if (unordered) {
|
|
94
|
-
return { ordered: false, indent: unordered[1].length }
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// ęåŗå蔨: 1. 2) ē
|
|
98
|
-
const ordered = line.match(RE_ORDERED_LIST)
|
|
99
|
-
if (ordered) {
|
|
100
|
-
return { ordered: true, indent: ordered[1].length }
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return null
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* ę£ęµęÆå¦ęÆå¼ēØåå¼å§
|
|
108
|
-
*/
|
|
109
|
-
export function isBlockquoteStart(line: string): boolean {
|
|
110
|
-
return RE_BLOCKQUOTE.test(line)
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* ę£ęµęÆå¦ęÆ HTML å
|
|
115
|
-
*/
|
|
116
|
-
export function isHtmlBlock(line: string): boolean {
|
|
117
|
-
return RE_HTML_BLOCK_1.test(line) || RE_HTML_BLOCK_2.test(line)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* ę£ęµč”Øę ¼åéč”
|
|
122
|
-
*/
|
|
123
|
-
export function isTableDelimiter(line: string): boolean {
|
|
124
|
-
return RE_TABLE_DELIMITER.test(line.trim())
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// ============ č注ę£ęµ ============
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* ę£ęµęÆå¦ęÆč注å®ä¹ēčµ·å§č”
|
|
131
|
-
* ę ¼å¼: [^id]: content
|
|
132
|
-
*
|
|
133
|
-
* @example
|
|
134
|
-
* isFootnoteDefinitionStart('[^1]: č注å
容') // true
|
|
135
|
-
* isFootnoteDefinitionStart('[^note]: å
容') // true
|
|
136
|
-
* isFootnoteDefinitionStart(' 缩čæå
容') // false
|
|
137
|
-
*/
|
|
138
|
-
export function isFootnoteDefinitionStart(line: string): boolean {
|
|
139
|
-
return RE_FOOTNOTE_DEFINITION.test(line)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* ę£ęµęÆå¦ęÆč注å®ä¹ēå»¶ē»č”ļ¼ē¼©čæč”ļ¼
|
|
144
|
-
* č³å°4äøŖē©ŗę ¼ę1äøŖtab
|
|
145
|
-
*
|
|
146
|
-
* @example
|
|
147
|
-
* isFootnoteContinuation(' 第äŗč”') // true
|
|
148
|
-
* isFootnoteContinuation('\t第äŗč”') // true
|
|
149
|
-
* isFootnoteContinuation(' äø¤äøŖē©ŗę ¼') // false
|
|
150
|
-
*/
|
|
151
|
-
export function isFootnoteContinuation(line: string): boolean {
|
|
152
|
-
return RE_FOOTNOTE_CONTINUATION.test(line)
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// ============ 容åØę£ęµ ============
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* ę£ęµå®¹åØå¼å§ęē»ę
|
|
159
|
-
*
|
|
160
|
-
* ęÆęę ¼å¼ļ¼
|
|
161
|
-
* - ::: name å¼å§
|
|
162
|
-
* - ::: name attr å¼å§ļ¼åø¦å±ę§ļ¼
|
|
163
|
-
* - ::: ē»ę
|
|
164
|
-
* - :::::: name å¼å§ļ¼ę“éæēę č®°ļ¼ēØäŗåµå„ļ¼
|
|
165
|
-
*/
|
|
166
|
-
export function detectContainer(line: string, config?: ContainerConfig): ContainerMatch | null {
|
|
167
|
-
const marker = config?.marker || ':'
|
|
168
|
-
const minLength = config?.minMarkerLength || 3
|
|
169
|
-
|
|
170
|
-
// 使ēØē¼åēę£å蔨达å¼
|
|
171
|
-
const cacheKey = `${marker}-${minLength}`
|
|
172
|
-
let pattern = containerPatternCache.get(cacheKey)
|
|
173
|
-
if (!pattern) {
|
|
174
|
-
const escapedMarker = marker.replace(RE_ESCAPE_SPECIAL, '\\$&')
|
|
175
|
-
pattern = new RegExp(
|
|
176
|
-
`^(\\s*)(${escapedMarker}{${minLength},})(?:\\s+(\\w[\\w-]*))?(?:\\s+(.*))?\\s*$`
|
|
177
|
-
)
|
|
178
|
-
containerPatternCache.set(cacheKey, pattern)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const match = line.match(pattern)
|
|
182
|
-
if (!match) {
|
|
183
|
-
return null
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const markerLength = match[2].length
|
|
187
|
-
const name = match[3] || ''
|
|
188
|
-
const isEnd = !name && !match[4]
|
|
189
|
-
|
|
190
|
-
if (!isEnd && config?.allowedNames && config.allowedNames.length > 0) {
|
|
191
|
-
if (!config.allowedNames.includes(name)) {
|
|
192
|
-
return null
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return { name, markerLength, isEnd }
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* ę£ęµå®¹åØē»ę
|
|
201
|
-
*/
|
|
202
|
-
export function detectContainerEnd(
|
|
203
|
-
line: string,
|
|
204
|
-
context: BlockContext,
|
|
205
|
-
config?: ContainerConfig
|
|
206
|
-
): boolean {
|
|
207
|
-
if (!context.inContainer || !context.containerMarkerLength) {
|
|
208
|
-
return false
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const result = detectContainer(line, config)
|
|
212
|
-
if (!result) {
|
|
213
|
-
return false
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return result.isEnd && result.markerLength >= context.containerMarkerLength
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// ============ č¾¹ēę£ęµ ============
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* å¤ęäø¤č”ä¹é“ęÆå¦ęęåč¾¹ē
|
|
223
|
-
*/
|
|
224
|
-
export function isBlockBoundary(
|
|
225
|
-
prevLine: string,
|
|
226
|
-
currentLine: string,
|
|
227
|
-
context: BlockContext
|
|
228
|
-
): boolean {
|
|
229
|
-
if (context.inFencedCode) {
|
|
230
|
-
return detectFenceEnd(currentLine, context)
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (isEmptyLine(prevLine) && !isEmptyLine(currentLine)) {
|
|
234
|
-
return true
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (isHeading(currentLine) && !isEmptyLine(prevLine)) {
|
|
238
|
-
return true
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (isThematicBreak(currentLine)) {
|
|
242
|
-
return true
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (detectFenceStart(currentLine)) {
|
|
246
|
-
return true
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
return false
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// ============ äøäøęē®”ē ============
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* å建åå§äøäøę
|
|
256
|
-
*/
|
|
257
|
-
export function createInitialContext(): BlockContext {
|
|
258
|
-
return {
|
|
259
|
-
inFencedCode: false,
|
|
260
|
-
listDepth: 0,
|
|
261
|
-
blockquoteDepth: 0,
|
|
262
|
-
inContainer: false,
|
|
263
|
-
containerDepth: 0
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* ę“ę°äøäøęļ¼å¤ēäøč”åļ¼
|
|
269
|
-
*/
|
|
270
|
-
export function updateContext(
|
|
271
|
-
line: string,
|
|
272
|
-
context: BlockContext,
|
|
273
|
-
containerConfig?: ContainerConfig | boolean
|
|
274
|
-
): BlockContext {
|
|
275
|
-
const newContext = { ...context }
|
|
276
|
-
|
|
277
|
-
const containerCfg =
|
|
278
|
-
containerConfig === true ? {} : containerConfig === false ? undefined : containerConfig
|
|
279
|
-
|
|
280
|
-
// 代ē åä¼å
ēŗ§ęé«
|
|
281
|
-
if (context.inFencedCode) {
|
|
282
|
-
if (detectFenceEnd(line, context)) {
|
|
283
|
-
newContext.inFencedCode = false
|
|
284
|
-
newContext.fenceChar = undefined
|
|
285
|
-
newContext.fenceLength = undefined
|
|
286
|
-
}
|
|
287
|
-
return newContext
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
const fence = detectFenceStart(line)
|
|
291
|
-
if (fence) {
|
|
292
|
-
newContext.inFencedCode = true
|
|
293
|
-
newContext.fenceChar = fence.char
|
|
294
|
-
newContext.fenceLength = fence.length
|
|
295
|
-
return newContext
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// 容åØå¤ē
|
|
299
|
-
if (containerCfg !== undefined) {
|
|
300
|
-
if (context.inContainer) {
|
|
301
|
-
if (detectContainerEnd(line, context, containerCfg)) {
|
|
302
|
-
newContext.containerDepth = context.containerDepth - 1
|
|
303
|
-
if (newContext.containerDepth === 0) {
|
|
304
|
-
newContext.inContainer = false
|
|
305
|
-
newContext.containerMarkerLength = undefined
|
|
306
|
-
newContext.containerName = undefined
|
|
307
|
-
}
|
|
308
|
-
return newContext
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
const nested = detectContainer(line, containerCfg)
|
|
312
|
-
if (nested && !nested.isEnd) {
|
|
313
|
-
newContext.containerDepth = context.containerDepth + 1
|
|
314
|
-
return newContext
|
|
315
|
-
}
|
|
316
|
-
} else {
|
|
317
|
-
const container = detectContainer(line, containerCfg)
|
|
318
|
-
if (container && !container.isEnd) {
|
|
319
|
-
newContext.inContainer = true
|
|
320
|
-
newContext.containerMarkerLength = container.markerLength
|
|
321
|
-
newContext.containerName = container.name
|
|
322
|
-
newContext.containerDepth = 1
|
|
323
|
-
return newContext
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
return newContext
|
|
329
|
-
}
|
|
330
|
-
|