@peaceroad/markdown-it-strong-ja 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
- const CHAR_ASTERISK = 0x2A // *
2
- const CHAR_SPACE = 0x20 // ' '
3
- const CHAR_TAB = 0x09 // '\t'
4
- const CHAR_NEWLINE = 0x0A // '\n'
5
- const CHAR_IDEOGRAPHIC_SPACE = 0x3000 // fullwidth space
6
- const MODE_FLAG_COMPATIBLE = 1 << 0
7
- const MODE_FLAG_AGGRESSIVE = 1 << 1
1
+ const CHAR_ASTERISK = 0x2A // *
2
+ const CHAR_SPACE = 0x20 // ' '
3
+ const CHAR_TAB = 0x09 // '\t'
4
+ const CHAR_NEWLINE = 0x0A // '\n'
5
+ const CHAR_IDEOGRAPHIC_SPACE = 0x3000 // fullwidth space
6
+ const MODE_FLAG_COMPATIBLE = 1 << 0
7
+ const MODE_FLAG_AGGRESSIVE = 1 << 1
8
8
  const MODE_FLAG_JAPANESE_BASE = 1 << 2
9
9
  const MODE_FLAG_JAPANESE_PLUS = 1 << 3
10
10
  const MODE_FLAG_JAPANESE_ANY = MODE_FLAG_JAPANESE_BASE | MODE_FLAG_JAPANESE_PLUS
@@ -16,23 +16,100 @@ const VALID_CANONICAL_MODES = new Set([
16
16
  'japanese-boundary',
17
17
  'japanese-boundary-guard'
18
18
  ])
19
- const REG_JAPANESE = /[\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Han}\u3000-\u303F\uFF00-\uFFEF]/u
20
- const REG_ATTRS = /{[^{}\n!@#%^&*()]+?}$/
21
-
19
+ const REG_JAPANESE = /[\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Han}\u3000-\u303F\uFF00-\uFFEF]/u
20
+ const REG_ATTRS = /{[^{}\n!@#%^&*()]+?}$/
21
+ const CHAR_REPLACEMENT = 0xFFFD
22
+
23
+ const isHighSurrogate = (code) => code >= 0xD800 && code <= 0xDBFF
24
+ const isLowSurrogate = (code) => code >= 0xDC00 && code <= 0xDFFF
25
+
26
+ const combineSurrogates = (high, low) => {
27
+ return 0x10000 + ((high - 0xD800) << 10) + (low - 0xDC00)
28
+ }
29
+
30
+ const codePointAtSafe = (src, index, fallback = 0) => {
31
+ if (typeof src !== 'string' || index < 0 || index >= src.length) return fallback
32
+ const first = src.charCodeAt(index)
33
+ if (first < 0xD800 || first > 0xDFFF) return first
34
+ if (first <= 0xDBFF) {
35
+ const second = index + 1 < src.length ? src.charCodeAt(index + 1) : 0
36
+ return isLowSurrogate(second) ? combineSurrogates(first, second) : CHAR_REPLACEMENT
37
+ }
38
+ return CHAR_REPLACEMENT
39
+ }
40
+
41
+ const codePointBeforeSafe = (src, index, fallback = 0) => {
42
+ if (typeof src !== 'string' || index <= 0 || index > src.length) return fallback
43
+ const last = src.charCodeAt(index - 1)
44
+ if (last < 0xD800 || last > 0xDFFF) return last
45
+ if (last >= 0xDC00) {
46
+ const first = index - 2 >= 0 ? src.charCodeAt(index - 2) : 0
47
+ return isHighSurrogate(first) ? combineSurrogates(first, last) : CHAR_REPLACEMENT
48
+ }
49
+ return CHAR_REPLACEMENT
50
+ }
51
+
52
+ const codePointStartBefore = (src, index) => {
53
+ if (typeof src !== 'string' || index <= 0 || index > src.length) return -1
54
+ const lastIdx = index - 1
55
+ const last = src.charCodeAt(lastIdx)
56
+ if (isLowSurrogate(last) && lastIdx - 1 >= 0 && isHighSurrogate(src.charCodeAt(lastIdx - 1))) {
57
+ return lastIdx - 1
58
+ }
59
+ return lastIdx
60
+ }
61
+
62
+ const codePointSize = (code) => code > 0xFFFF ? 2 : 1
63
+
64
+ const isAstralJapaneseCode = (code) => {
65
+ return (code >= 0x1AFF0 && code <= 0x1AFFF) || // Kana Extended-B
66
+ (code >= 0x1B000 && code <= 0x1B0FF) || // Kana Supplement
67
+ (code >= 0x1B100 && code <= 0x1B12F) || // Kana Extended-A
68
+ (code >= 0x1B130 && code <= 0x1B16F) || // Small Kana Extension
69
+ (code >= 0x20000 && code <= 0x2A6DF) || // CJK Unified Ideographs Extension B
70
+ (code >= 0x2A700 && code <= 0x2B73F) || // Extension C
71
+ (code >= 0x2B740 && code <= 0x2B81F) || // Extension D
72
+ (code >= 0x2B820 && code <= 0x2CEAF) || // Extension E
73
+ (code >= 0x2CEB0 && code <= 0x2EBEF) || // Extension F
74
+ (code >= 0x2EBF0 && code <= 0x2EE5F) || // Extension I
75
+ (code >= 0x2F800 && code <= 0x2FA1F) || // CJK Compatibility Ideographs Supplement
76
+ (code >= 0x30000 && code <= 0x3134F) || // Extension G
77
+ (code >= 0x31350 && code <= 0x323AF) // Extension H
78
+ }
79
+
22
80
  const isJapaneseChar = (ch) => {
23
- if (!ch) return false
24
- const code = typeof ch === 'string' ? ch.charCodeAt(0) : ch
25
- if (code < 128) return false
26
- if (code >= 0x3040 && code <= 0x309F) return true
27
- if (code >= 0x30A0 && code <= 0x30FF) return true
28
- // Han + CJK punctuation/fullwidth ranges are common hot-path hits.
29
- // Keep these as cheap numeric checks before the fallback regex.
30
- if (code >= 0x3400 && code <= 0x4DBF) return true
31
- if (code >= 0x4E00 && code <= 0x9FFF) return true
32
- if (code >= 0xF900 && code <= 0xFAFF) return true
33
- if (code >= 0x3000 && code <= 0x303F) return true
34
- if (code >= 0xFF00 && code <= 0xFFEF) return true
35
- return REG_JAPANESE.test(String.fromCharCode(code))
81
+ if (!ch) return false
82
+ const code = typeof ch === 'string' ? ch.codePointAt(0) : ch
83
+ if (!Number.isFinite(code)) return false
84
+ if (code < 128) return false
85
+ if (code >= 0x3040 && code <= 0x309F) return true
86
+ if (code >= 0x30A0 && code <= 0x30FF) return true
87
+ // Han + CJK punctuation/fullwidth ranges are common hot-path hits.
88
+ // Keep these as cheap numeric checks before the fallback regex.
89
+ if (code >= 0x3400 && code <= 0x4DBF) return true
90
+ if (code >= 0x4E00 && code <= 0x9FFF) return true
91
+ if (code >= 0xF900 && code <= 0xFAFF) return true
92
+ if (code >= 0x3000 && code <= 0x303F) return true
93
+ if (code >= 0xFF00 && code <= 0xFFEF) return true
94
+ if (code > 0x10FFFF) return false
95
+ if (code >= 0x10000 && isAstralJapaneseCode(code)) return true
96
+ if (code >= 0x10000 && code < 0x20000) return false
97
+ return REG_JAPANESE.test(String.fromCodePoint(code))
98
+ }
99
+
100
+ const isAsciiWordCode = (code) => {
101
+ return (code >= 0x30 && code <= 0x39) ||
102
+ (code >= 0x41 && code <= 0x5A) ||
103
+ (code >= 0x61 && code <= 0x7A)
104
+ }
105
+
106
+ const isSoftSpaceCode = (code) => {
107
+ return code === CHAR_SPACE || code === CHAR_TAB || code === CHAR_IDEOGRAPHIC_SPACE
108
+ }
109
+
110
+ const cloneMap = (map) => {
111
+ if (!map || !Array.isArray(map)) return null
112
+ return [map[0], map[1]]
36
113
  }
37
114
 
38
115
  const hasCjkBreaksRule = (md) => {
@@ -59,7 +136,7 @@ const hasCjkBreaksRule = (md) => {
59
136
  const isCjkBreaksRuleName = (name) => {
60
137
  return typeof name === 'string' && REG_CJK_BREAKS_RULE_NAME.test(name)
61
138
  }
62
-
139
+
63
140
  const resolveMode = (opt) => {
64
141
  const raw = opt && typeof opt.mode === 'string' ? opt.mode : 'japanese'
65
142
  const normalized = raw.toLowerCase()
@@ -70,9 +147,9 @@ const resolveMode = (opt) => {
70
147
  `mditStrongJa: unknown mode "${raw}". Valid modes: japanese, japanese-boundary, japanese-boundary-guard, aggressive, compatible`
71
148
  )
72
149
  }
73
-
74
- const getModeFlags = (mode) => {
75
- switch (mode) {
150
+
151
+ const getModeFlags = (mode) => {
152
+ switch (mode) {
76
153
  case 'compatible':
77
154
  return MODE_FLAG_COMPATIBLE
78
155
  case 'aggressive':
@@ -81,26 +158,26 @@ const getModeFlags = (mode) => {
81
158
  return MODE_FLAG_JAPANESE_BASE
82
159
  case 'japanese-boundary-guard':
83
160
  return MODE_FLAG_JAPANESE_PLUS
84
- default:
85
- return 0
86
- }
87
- }
88
-
89
- const deriveModeInfo = (opt) => {
90
- if (!opt || typeof opt !== 'object') return opt
91
- const rawMode = opt.mode
92
- if (opt.__strongJaModeRaw === rawMode &&
93
- typeof opt.__strongJaMode === 'string' &&
94
- typeof opt.__strongJaModeFlags === 'number') {
95
- return opt
96
- }
97
- const mode = resolveMode(opt)
98
- opt.__strongJaModeRaw = rawMode
99
- opt.__strongJaMode = mode
100
- opt.__strongJaModeFlags = getModeFlags(mode)
101
- return opt
102
- }
103
-
161
+ default:
162
+ return 0
163
+ }
164
+ }
165
+
166
+ const deriveModeInfo = (opt) => {
167
+ if (!opt || typeof opt !== 'object') return opt
168
+ const rawMode = opt.mode
169
+ if (opt.__strongJaModeRaw === rawMode &&
170
+ typeof opt.__strongJaMode === 'string' &&
171
+ typeof opt.__strongJaModeFlags === 'number') {
172
+ return opt
173
+ }
174
+ const mode = resolveMode(opt)
175
+ opt.__strongJaModeRaw = rawMode
176
+ opt.__strongJaMode = mode
177
+ opt.__strongJaModeFlags = getModeFlags(mode)
178
+ return opt
179
+ }
180
+
104
181
  const deriveOptionInfo = (opt) => {
105
182
  if (!opt || typeof opt !== 'object') return opt
106
183
  deriveModeInfo(opt)
@@ -135,21 +212,29 @@ const hasRuntimeOverride = (override) => {
135
212
 
136
213
  const getRuntimeOpt = (state, baseOpt) => {
137
214
  const override = state && state.env ? state.env.__strongJaTokenOpt : null
138
- if (!hasRuntimeOverride(override)) return deriveOptionInfo(baseOpt)
139
- if (state.__strongJaTokenRuntimeOpt &&
215
+ const hasOverride = hasRuntimeOverride(override)
216
+ if (state &&
217
+ state.__strongJaTokenRuntimeOpt &&
140
218
  state.__strongJaTokenRuntimeBase === baseOpt &&
141
- state.__strongJaTokenRuntimeOverride === override) {
219
+ state.__strongJaTokenRuntimeOverride === override &&
220
+ state.__strongJaTokenRuntimeHasOverride === hasOverride) {
142
221
  return state.__strongJaTokenRuntimeOpt
143
222
  }
144
- const merged = baseOpt && typeof baseOpt === 'object' ? { ...baseOpt } : {}
145
- if (HAS_OWN.call(override, 'mode') && override.mode !== undefined) merged.mode = override.mode
146
- if (HAS_OWN.call(override, 'postprocess') && override.postprocess !== undefined) merged.postprocess = override.postprocess
147
- state.__strongJaTokenRuntimeOpt = deriveOptionInfo(merged)
223
+ let resolved = deriveOptionInfo(baseOpt)
224
+ if (hasOverride) {
225
+ const merged = baseOpt && typeof baseOpt === 'object' ? { ...baseOpt } : {}
226
+ if (HAS_OWN.call(override, 'mode') && override.mode !== undefined) merged.mode = override.mode
227
+ if (HAS_OWN.call(override, 'postprocess') && override.postprocess !== undefined) merged.postprocess = override.postprocess
228
+ resolved = deriveOptionInfo(merged)
229
+ }
230
+ if (!state) return resolved
231
+ state.__strongJaTokenRuntimeOpt = resolved
148
232
  state.__strongJaTokenRuntimeBase = baseOpt
149
233
  state.__strongJaTokenRuntimeOverride = override
150
- return state.__strongJaTokenRuntimeOpt
234
+ state.__strongJaTokenRuntimeHasOverride = hasOverride
235
+ return resolved
151
236
  }
152
-
237
+
153
238
  const getReferenceCount = (state) => {
154
239
  if (!state) return 0
155
240
  let referenceCount = state.__strongJaReferenceCount
@@ -167,74 +252,81 @@ const getReferenceCount = (state) => {
167
252
  return referenceCount
168
253
  }
169
254
 
170
- function normalizeCoreRulesBeforePostprocess(value) {
171
- if (!value) return []
172
- const list = Array.isArray(value) ? value : [value]
173
- const normalized = []
174
- const seen = new Set()
175
- for (let idx = 0; idx < list.length; idx++) {
176
- const raw = list[idx]
177
- if (typeof raw !== 'string') continue
178
- const trimmed = raw.trim()
179
- if (!trimmed || seen.has(trimmed)) continue
180
- seen.add(trimmed)
181
- normalized.push(trimmed)
182
- }
183
- return normalized
184
- }
185
-
186
- function ensureCoreRuleOrder(md, ruleNames, targetRuleName) {
187
- if (!md || !md.core || !md.core.ruler) return
188
- if (!ruleNames || ruleNames.length === 0) return
189
- for (let idx = 0; idx < ruleNames.length; idx++) {
190
- moveRuleBefore(md.core.ruler, ruleNames[idx], targetRuleName)
191
- }
192
- }
193
-
194
- function moveRuleBefore(ruler, ruleName, beforeName) {
195
- if (!ruler || !ruler.__rules__) return
196
- const rules = ruler.__rules__
197
- let fromIdx = -1
198
- let beforeIdx = -1
199
- for (let idx = 0; idx < rules.length; idx++) {
200
- if (rules[idx].name === ruleName) fromIdx = idx
201
- if (rules[idx].name === beforeName) beforeIdx = idx
202
- if (fromIdx !== -1 && beforeIdx !== -1) break
203
- }
204
- // Ensure ruleName is before beforeName; keep existing order if already earlier.
205
- if (fromIdx === -1 || beforeIdx === -1 || fromIdx < beforeIdx) return
206
-
207
- const rule = rules.splice(fromIdx, 1)[0]
208
- rules.splice(beforeIdx, 0, rule)
209
- ruler.__cache__ = null
210
- }
211
-
212
- function moveRuleAfter(ruler, ruleName, afterName) {
213
- if (!ruler || !ruler.__rules__) return
214
- const rules = ruler.__rules__
215
- let fromIdx = -1
216
- let afterIdx = -1
217
- for (let idx = 0; idx < rules.length; idx++) {
218
- if (rules[idx].name === ruleName) fromIdx = idx
219
- if (rules[idx].name === afterName) afterIdx = idx
220
- if (fromIdx !== -1 && afterIdx !== -1) break
221
- }
222
- if (fromIdx === -1 || afterIdx === -1 || fromIdx === afterIdx + 1) return
223
-
224
- const rule = rules.splice(fromIdx, 1)[0]
225
- const targetIdx = fromIdx < afterIdx ? afterIdx - 1 : afterIdx
226
- rules.splice(targetIdx + 1, 0, rule)
227
- ruler.__cache__ = null
228
- }
229
-
230
- export {
231
- CHAR_ASTERISK,
232
- CHAR_SPACE,
233
- CHAR_TAB,
234
- CHAR_NEWLINE,
235
- CHAR_IDEOGRAPHIC_SPACE,
255
+ function normalizeCoreRulesBeforePostprocess(value) {
256
+ if (!value) return []
257
+ const list = Array.isArray(value) ? value : [value]
258
+ const normalized = []
259
+ const seen = new Set()
260
+ for (let idx = 0; idx < list.length; idx++) {
261
+ const raw = list[idx]
262
+ if (typeof raw !== 'string') continue
263
+ const trimmed = raw.trim()
264
+ if (!trimmed || seen.has(trimmed)) continue
265
+ seen.add(trimmed)
266
+ normalized.push(trimmed)
267
+ }
268
+ return normalized
269
+ }
270
+
271
+ function ensureCoreRuleOrder(md, ruleNames, targetRuleName) {
272
+ if (!md || !md.core || !md.core.ruler) return
273
+ if (!ruleNames || ruleNames.length === 0) return
274
+ for (let idx = 0; idx < ruleNames.length; idx++) {
275
+ moveRuleBefore(md.core.ruler, ruleNames[idx], targetRuleName)
276
+ }
277
+ }
278
+
279
+ function moveRuleBefore(ruler, ruleName, beforeName) {
280
+ if (!ruler || !ruler.__rules__) return
281
+ const rules = ruler.__rules__
282
+ let fromIdx = -1
283
+ let beforeIdx = -1
284
+ for (let idx = 0; idx < rules.length; idx++) {
285
+ if (rules[idx].name === ruleName) fromIdx = idx
286
+ if (rules[idx].name === beforeName) beforeIdx = idx
287
+ if (fromIdx !== -1 && beforeIdx !== -1) break
288
+ }
289
+ // Ensure ruleName is before beforeName; keep existing order if already earlier.
290
+ if (fromIdx === -1 || beforeIdx === -1 || fromIdx < beforeIdx) return
291
+
292
+ const rule = rules.splice(fromIdx, 1)[0]
293
+ rules.splice(beforeIdx, 0, rule)
294
+ ruler.__cache__ = null
295
+ }
296
+
297
+ function moveRuleAfter(ruler, ruleName, afterName) {
298
+ if (!ruler || !ruler.__rules__) return
299
+ const rules = ruler.__rules__
300
+ let fromIdx = -1
301
+ let afterIdx = -1
302
+ for (let idx = 0; idx < rules.length; idx++) {
303
+ if (rules[idx].name === ruleName) fromIdx = idx
304
+ if (rules[idx].name === afterName) afterIdx = idx
305
+ if (fromIdx !== -1 && afterIdx !== -1) break
306
+ }
307
+ if (fromIdx === -1 || afterIdx === -1 || fromIdx === afterIdx + 1) return
308
+
309
+ const rule = rules.splice(fromIdx, 1)[0]
310
+ const targetIdx = fromIdx < afterIdx ? afterIdx - 1 : afterIdx
311
+ rules.splice(targetIdx + 1, 0, rule)
312
+ ruler.__cache__ = null
313
+ }
314
+
315
+ export {
316
+ CHAR_ASTERISK,
317
+ CHAR_SPACE,
318
+ CHAR_TAB,
319
+ CHAR_NEWLINE,
320
+ CHAR_IDEOGRAPHIC_SPACE,
236
321
  REG_ATTRS,
322
+ codePointAtSafe,
323
+ codePointBeforeSafe,
324
+ codePointStartBefore,
325
+ codePointSize,
237
326
  isJapaneseChar,
327
+ isAsciiWordCode,
328
+ isSoftSpaceCode,
329
+ cloneMap,
238
330
  hasCjkBreaksRule,
239
331
  isCjkBreaksRuleName,
240
332
  resolveMode,
@@ -243,14 +335,14 @@ export {
243
335
  deriveOptionInfo,
244
336
  hasRuntimeOverride,
245
337
  MODE_FLAG_COMPATIBLE,
246
- MODE_FLAG_AGGRESSIVE,
247
- MODE_FLAG_JAPANESE_BASE,
248
- MODE_FLAG_JAPANESE_PLUS,
338
+ MODE_FLAG_AGGRESSIVE,
339
+ MODE_FLAG_JAPANESE_BASE,
340
+ MODE_FLAG_JAPANESE_PLUS,
249
341
  MODE_FLAG_JAPANESE_ANY,
250
342
  getRuntimeOpt,
251
343
  getReferenceCount,
252
- normalizeCoreRulesBeforePostprocess,
253
- ensureCoreRuleOrder,
254
- moveRuleBefore,
255
- moveRuleAfter
256
- }
344
+ normalizeCoreRulesBeforePostprocess,
345
+ ensureCoreRuleOrder,
346
+ moveRuleBefore,
347
+ moveRuleAfter
348
+ }