@peaceroad/markdown-it-numbering-ul-regarded-as-ol 0.2.3 → 0.4.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/README.md +20 -5
- package/index.js +38 -54
- package/package.json +2 -2
- package/src/phase0-description-list.js +232 -113
- package/src/phase1-analyze.js +39 -8
- package/src/phase2-convert.js +177 -193
- package/src/phase3-attributes.js +24 -47
- package/src/phase5-spans.js +73 -54
- package/src/preprocess-literal-lists.js +295 -362
- package/src/types-utility.js +0 -15
- package/src/phase6-attrs-migration.js +0 -184
package/src/types-utility.js
CHANGED
|
@@ -371,21 +371,6 @@ const createMarkerResult = (type, marker, number, prefix, suffix) => ({
|
|
|
371
371
|
suffix
|
|
372
372
|
})
|
|
373
373
|
|
|
374
|
-
/**
|
|
375
|
-
* Try to match content against compiled type patterns
|
|
376
|
-
* @param {string} trimmed - Trimmed content
|
|
377
|
-
* @param {Object} compiledType - Compiled type info
|
|
378
|
-
* @param {Object} typeInfo - Type info from listTypes.json
|
|
379
|
-
* @returns {Object|null} Match result or null
|
|
380
|
-
*/
|
|
381
|
-
const tryMatchPattern = (trimmed, compiledType, typeInfo) => {
|
|
382
|
-
for (const pattern of compiledType.patterns) {
|
|
383
|
-
const m = matchRegexEntry(trimmed, compiledType.name, pattern)
|
|
384
|
-
if (m) return m
|
|
385
|
-
}
|
|
386
|
-
return null
|
|
387
|
-
}
|
|
388
|
-
|
|
389
374
|
// Enhanced marker type detection with context awareness
|
|
390
375
|
export const detectMarkerType = (content, allContents = null) => {
|
|
391
376
|
let contextResult = null
|
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
// Phase 6: Attribute Migration
|
|
2
|
-
// Runs after markdown-it-attrs processing to handle nested list attributes
|
|
3
|
-
// This phase moves custom attributes from child lists to parent lists
|
|
4
|
-
// in flattened `- 1. Parent\n - a. Child\n{.class}` patterns
|
|
5
|
-
|
|
6
|
-
import { buildListCloseIndexMap } from './list-helpers.js'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Move custom attributes from nested child ordered_list to parent ordered_list
|
|
10
|
-
*
|
|
11
|
-
* Background:
|
|
12
|
-
* - Plugin flattens `ul > li > ol` structure to `ol > li` (simplifyNestedBulletLists)
|
|
13
|
-
* - markdown-it-attrs runs on original structure, applies {.class} to child list
|
|
14
|
-
* - Users expect {.class} after nested list to apply to parent list
|
|
15
|
-
*
|
|
16
|
-
* Algorithm:
|
|
17
|
-
* 1. Find top-level ordered_list_open tokens (level 0 or 2)
|
|
18
|
-
* 2. Locate child ordered_list_open within first list_item
|
|
19
|
-
* 3. Extract custom attributes (exclude plugin-generated: type, data-marker-*, role, ol-* classes)
|
|
20
|
-
* 4. Move custom classes to parent's class list
|
|
21
|
-
* 5. Move other custom attrs to parent
|
|
22
|
-
* 6. Remove moved attrs from child
|
|
23
|
-
*
|
|
24
|
-
* @param {Array} tokens - Token array to process
|
|
25
|
-
*/
|
|
26
|
-
export function moveNestedListAttributes(tokens) {
|
|
27
|
-
const tokensLength = tokens.length
|
|
28
|
-
const closeMap = buildListCloseIndexMap(tokens)
|
|
29
|
-
const listCloseByOpen = closeMap.listCloseByOpen
|
|
30
|
-
const listItemCloseByOpen = closeMap.listItemCloseByOpen
|
|
31
|
-
|
|
32
|
-
// Single pass: find top-level ordered_lists and process immediately
|
|
33
|
-
for (let i = 0; i < tokensLength; i++) {
|
|
34
|
-
const token = tokens[i]
|
|
35
|
-
|
|
36
|
-
// Skip non-top-level ordered lists
|
|
37
|
-
if (token.type !== 'ordered_list_open' || (token.level !== 0 && token.level !== 2)) {
|
|
38
|
-
continue
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const parentToken = token
|
|
42
|
-
const parentLevel = token.level
|
|
43
|
-
|
|
44
|
-
// Find list end
|
|
45
|
-
let listEndIndex = listCloseByOpen[i]
|
|
46
|
-
if (typeof listEndIndex !== 'number' || listEndIndex === -1) {
|
|
47
|
-
listEndIndex = tokensLength
|
|
48
|
-
let depth = 1
|
|
49
|
-
for (let j = i + 1; j < tokensLength; j++) {
|
|
50
|
-
if (tokens[j].type === 'ordered_list_open') depth++
|
|
51
|
-
else if (tokens[j].type === 'ordered_list_close') {
|
|
52
|
-
depth--
|
|
53
|
-
if (depth === 0) {
|
|
54
|
-
listEndIndex = j
|
|
55
|
-
break
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Find first list_item
|
|
62
|
-
let firstItemOpen = -1
|
|
63
|
-
let firstItemClose = -1
|
|
64
|
-
|
|
65
|
-
for (let j = i + 1; j < listEndIndex; j++) {
|
|
66
|
-
const t = tokens[j]
|
|
67
|
-
|
|
68
|
-
if (t.type === 'list_item_open' && t.level === parentLevel + 1) {
|
|
69
|
-
firstItemOpen = j
|
|
70
|
-
firstItemClose = listItemCloseByOpen[j]
|
|
71
|
-
if (typeof firstItemClose !== 'number' || firstItemClose === -1) {
|
|
72
|
-
// Find matching close
|
|
73
|
-
let itemDepth = 1
|
|
74
|
-
for (let k = j + 1; k < tokensLength; k++) {
|
|
75
|
-
if (tokens[k].type === 'list_item_open') itemDepth++
|
|
76
|
-
else if (tokens[k].type === 'list_item_close') {
|
|
77
|
-
itemDepth--
|
|
78
|
-
if (itemDepth === 0) {
|
|
79
|
-
firstItemClose = k
|
|
80
|
-
break
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
break
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (firstItemOpen === -1 || firstItemClose === -1) continue
|
|
90
|
-
|
|
91
|
-
// Find child ordered_list within first list_item
|
|
92
|
-
let childListOpen = -1
|
|
93
|
-
for (let j = firstItemOpen + 1; j < firstItemClose && j < tokensLength; j++) {
|
|
94
|
-
if (tokens[j].type === 'ordered_list_open' && tokens[j].level > parentLevel) {
|
|
95
|
-
childListOpen = j
|
|
96
|
-
break
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (childListOpen === -1) continue
|
|
101
|
-
|
|
102
|
-
const childToken = tokens[childListOpen]
|
|
103
|
-
if (!childToken.attrs || childToken.attrs.length === 0) continue
|
|
104
|
-
|
|
105
|
-
// Extract custom attributes (exclude plugin-generated)
|
|
106
|
-
const customAttrs = []
|
|
107
|
-
const remainingAttrs = []
|
|
108
|
-
|
|
109
|
-
for (let j = 0; j < childToken.attrs.length; j++) {
|
|
110
|
-
const [key, value] = childToken.attrs[j]
|
|
111
|
-
|
|
112
|
-
// Exclude plugin-generated attributes
|
|
113
|
-
if (key === 'type' || key === 'role' || key === 'style' || key === 'start' || key.startsWith('data-marker-')) {
|
|
114
|
-
remainingAttrs.push([key, value])
|
|
115
|
-
continue
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Handle class attribute specially
|
|
119
|
-
if (key === 'class') {
|
|
120
|
-
const classes = value.split(/\s+/)
|
|
121
|
-
const pluginClasses = []
|
|
122
|
-
const customClasses = []
|
|
123
|
-
|
|
124
|
-
for (let k = 0; k < classes.length; k++) {
|
|
125
|
-
// Treat ol-* as plugin-generated (should remain on child)
|
|
126
|
-
if (classes[k].startsWith('ol-')) {
|
|
127
|
-
pluginClasses.push(classes[k])
|
|
128
|
-
} else {
|
|
129
|
-
customClasses.push(classes[k])
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (pluginClasses.length > 0) {
|
|
134
|
-
remainingAttrs.push(['class', pluginClasses.join(' ')])
|
|
135
|
-
}
|
|
136
|
-
if (customClasses.length > 0) {
|
|
137
|
-
customAttrs.push(['class', customClasses.join(' ')])
|
|
138
|
-
}
|
|
139
|
-
continue
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// All other attributes are custom
|
|
143
|
-
customAttrs.push([key, value])
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (customAttrs.length === 0) continue
|
|
147
|
-
|
|
148
|
-
// Move custom attributes to parent
|
|
149
|
-
if (!parentToken.attrs) {
|
|
150
|
-
parentToken.attrs = []
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Merge attributes
|
|
154
|
-
for (let j = 0; j < customAttrs.length; j++) {
|
|
155
|
-
const [key, value] = customAttrs[j]
|
|
156
|
-
|
|
157
|
-
if (key === 'class') {
|
|
158
|
-
// Find existing class attribute
|
|
159
|
-
let existingClassIdx = -1
|
|
160
|
-
for (let k = 0; k < parentToken.attrs.length; k++) {
|
|
161
|
-
if (parentToken.attrs[k][0] === 'class') {
|
|
162
|
-
existingClassIdx = k
|
|
163
|
-
break
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (existingClassIdx !== -1) {
|
|
168
|
-
const existingClasses = parentToken.attrs[existingClassIdx][1].split(/\s+/)
|
|
169
|
-
const newClasses = value.split(/\s+/)
|
|
170
|
-
// Use Set for deduplication
|
|
171
|
-
const mergedClasses = [...new Set([...existingClasses, ...newClasses])]
|
|
172
|
-
parentToken.attrs[existingClassIdx][1] = mergedClasses.join(' ')
|
|
173
|
-
} else {
|
|
174
|
-
parentToken.attrs.push(['class', value])
|
|
175
|
-
}
|
|
176
|
-
} else {
|
|
177
|
-
parentToken.attrs.push([key, value])
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Update child token attrs
|
|
182
|
-
childToken.attrs = remainingAttrs.length > 0 ? remainingAttrs : null
|
|
183
|
-
}
|
|
184
|
-
}
|