micromark-extension-cjk-friendly 1.2.3 → 2.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/README.md CHANGED
@@ -8,7 +8,7 @@ A [micromark](https://github.com/micromark/micromark) extension to make Markdown
8
8
 
9
9
  <span lang="zh-Hans-CN">一个 [micromark](https://github.com/micromark/micromark) 扩展,用于使 CommonMark 的强调标记(`**`)能够正确支持中文、日语和韩语文本。</span>
10
10
 
11
- <span lang="ko">CommonMark의 강조 표시(`**`) 를 한국어, 중국어, 일본어와 호환되도록 만드는 [micromark](https://github.com/micromark/micromark) 확장</span>
11
+ <span lang="ko">CommonMark의 강조 표시(`**`) 를 한국어, 일본어, 중국어와 호환되도록 만드는 [micromark](https://github.com/micromark/micromark) 확장.</span>
12
12
 
13
13
  > [!NOTE]
14
14
  > This package does not support the strikethrough syntax (`~~`) in GFM (GitHub Flavored Markdown). If you want to support it, please use [`micromark-extension-cjk-friendly-gfm-strikethrough`](https://npmjs.com/package/micromark-extension-cjk-friendly-gfm-strikethrough) along with this package.
@@ -19,7 +19,7 @@ A [micromark](https://github.com/micromark/micromark) extension to make Markdown
19
19
  >
20
20
  > <span lang="ko">이 패키지는 GitHub Flavored Markdown(GFM)의 취소선(`~~`)을 지원하지 않습니다. 지원하고 싶은 경우에는 [`micromark-extension-cjk-friendly-gfm-strikethrough`](https://npmjs.com/package/micromark-extension-cjk-friendly-gfm-strikethrough)를 함께 사용해 주세요.</span>
21
21
 
22
- ## Problem / <span lang="ja">問題</span> / <span lang="zh-Hans-CN">问题</span> / <span lang="ko">문제점</span>
22
+ ## Problem / <span lang="ja">問題</span> / <span lang="zh-Hans-CN">问题</span> / <span lang="ko">문제</span>
23
23
 
24
24
  CommonMark has a problem that the following emphasis marks `**` are not recognized as emphasis marks in Japanese, Chinese, and Korean.
25
25
 
@@ -27,7 +27,7 @@ CommonMark has a problem that the following emphasis marks `**` are not recogniz
27
27
 
28
28
  <span lang="zh-Hans-CN">CommonMark存在以下问题:在中文、日语和韩语文本中,强调标记`**`不会被识别为强调标记。</span>
29
29
 
30
- <span lang="ko">CommonMark는 일본어와 중국어에서 다음과 같은 강조 표시 `**`가 강조 표시로 인식되지 않는 문제가 있습니다.</span>
30
+ <span lang="ko">CommonMark는 한국어, 일본어, 중국어에서 다음과 같은 강조 표시 `**`가 강조 표시로 인식되지 않는 문제가 있습니다.</span>
31
31
 
32
32
  ```md
33
33
  **このアスタリスクは強調記号として認識されず、そのまま表示されます。**この文のせいで。
@@ -75,7 +75,7 @@ Additionally, if you are creating Markdown-related software or services primaril
75
75
  1. <span lang="ja">ユーザまたはAIが作成したコンテンツをそのまま表示する必要がある場合</span>
76
76
  2. <span lang="ja">翻訳者に、このCommonMarkの仕様を理解していない人も多く、なおかつリアルタイムで本番同様の描画プレビューを提供できず、`<strong>`タグを許可していない場合</span>
77
77
  - <span lang="ja">翻訳にCrowdin・Transifexなどの翻訳サービスを使っている場合</span>
78
- - <span lang="ja">翻訳の品質に責任を負っている人が非エンジニアである、またはComonMarkのこの挙動を理解していない場合</span>
78
+ - <span lang="ja">翻訳の品質に責任を負っている人が非エンジニアである、またはCommonMarkのこの挙動を理解していない場合</span>
79
79
 
80
80
  <span lang="ja">また、あなたが主に日本人・中国人・韓国人のいずれかまたは全てを対象としたMarkdown関連のソフトウェアやサービスを作成する場合も、このパッケージを使う(この仕様を採用する)ことを強く推奨します。</span>
81
81
 
@@ -88,24 +88,24 @@ Additionally, if you are creating Markdown-related software or services primaril
88
88
 
89
89
  <span lang="zh-Hans-CN">此外,如果您正在创建主要面向中国人、日本人或韩国人(或全部)的Markdown相关软件或服务,也强烈建议采用此规范。</span>
90
90
 
91
- <span lang="ko">엔지니어로서 완전히 감독할 수 없는 일본어, 중국어, 한국어 콘텐츠를 다뤄야 하는 경우, 이 패키지를 사용하세요 (일반 CommonMark나 GFM 대신 이 사양을 채택할 것을 강력히 권장합니다). "완전히 감독할 수 없는"이란 다음과 같은 상황을 의미합니다:</span>
91
+ <span lang="ko">엔지니어로서 완전히 감독할 수 없는 일본어, 중국어, 한국어 콘텐츠를 다뤄야 하는 경우 이 패키지를 사용(일반 CommonMark나 GFM 대신 이 사양을 채택)할 것을 강력히 권장합니다. '완전히 감독할 수 없는'이란 다음과 같은 상황을 의미합니다.</span>
92
92
 
93
93
  1. <span lang="ko">사용자 또는 AI가 생성한 콘텐츠를 그대로 표시해야 하는 경우</span>
94
- 2. <span lang="ko">많은 번역자가 CommonMark 동작을 이해하지 못하고, 실시간으로 실제 환경과 유사한 렌더링 미리보기를 제공할 수 없으며, `<strong>` 태그가 허용되지 않는 경우</span>
94
+ 2. <span lang="ko">많은 번역자가 CommonMark 동작을 이해하지 못하고, 실시간으로 실제 환경과 유사한 렌더링 미리보기를 제공할 수 없으며, `<strong>` 태그가 허용되지 않는 경우</span>
95
95
  - <span lang="ko">Crowdin이나 Transifex 같은 번역 서비스를 사용하는 경우</span>
96
- - <span lang="ko">번역 품질에 책임을 지는 사람이 엔지니어가 아니거나 CommonMark 동작을 이해하지 못하는 경우</span>
96
+ - <span lang="ko">번역 품질에 책임을 지는 사람이 엔지니어가 아니거나 CommonMark 동작을 이해하지 못하는 경우</span>
97
97
 
98
- <span lang="ko">또한, 주로 일본어, 중국어, 한국어 사용자(또는 모두)를 대상으로 하는 Markdown 관련 소프트웨어나 서비스를 만들고 있다면, 이 패키지를 사용하세요 (이 사양을 채택할 것을 강력히 권장합니다).</span>
98
+ <span lang="ko">또한, 주로 한국어, 일본어, 중국어 사용자(또는 모두)를 대상으로 하는 Markdown 관련 소프트웨어나 서비스를 만들고 있다면 이 패키지를 사용(이 사양을 채택)할 것을 강력히 권장합니다.</span>
99
99
 
100
- ## Runtime Requirements / <span lang="ja">実行環境の要件</span> / <span lang="zh-Hans-CN">运行环境要求</span> / <span lang="ko">업데이트 전략</span>
100
+ ## Runtime Requirements / <span lang="ja">実行環境の要件</span> / <span lang="zh-Hans-CN">运行环境要求</span> / <span lang="ko">런타임 요구 사항</span>
101
101
 
102
- This package is ESM-only. It requires Node.js 16 or later.
102
+ This package is ESM-only. It requires Node.js 18 or later. (I have only tested it on 20 and later. There is no factor that would prevent it from working on 18, but I do not guarantee its operation on 18.)
103
103
 
104
- <span lang="ja">本パッケージはESM専用です。Node.js 16以上が必要です。</span>
104
+ <span lang="ja">本パッケージはESM専用です。Node.js 18以上が必要です。(動作検証は20以降でのみ行っています。18での動作を妨げる要因はありませんが、動作の保証はありません)</span>
105
105
 
106
- <span lang="zh-Hans-CN">此包仅支持ESM。需要Node.js 16或更高版本。</span>
106
+ <span lang="zh-Hans-CN">此包仅支持ESM。需要Node.js 18或更高版本。(我只测试了20及以后的版本。没有因素会阻止它在18上工作,但我不保证在18上的操作。)</span>
107
107
 
108
- <span lang="ko">이 패키지는 ESM 사용을 위한 패키지입니다. Node.js 16或更高版本가 필요입니다.</span>
108
+ <span lang="ko">본 패키지는 ESM 전용입니다. Node.js 18 이상이 필요합니다. (동작 검증은 20 이후 버전에서만 수행했습니다. 18에서 동작을 방해하는 요인은 없으나, 동작을 보장하지는 않습니다)</span>
109
109
 
110
110
  ## Installation / <span lang="ja">インストール</span> / <span lang="zh-Hans-CN">安装</span> / <span lang="ko">설치</span>
111
111
 
@@ -127,7 +127,7 @@ If you use another package manager, please replace `npm install` with the comman
127
127
 
128
128
  <span lang="zh-Hans-CN">如果使用其他包管理器,请将 `npm install` 替换为当时包管理器的命令(例如:`pnpm add`、`yarn add`)。</span>
129
129
 
130
- <span lang="ko">다른 패키지 매니저를 사용하는 경우 `npm install`을 해당 패키지 매니저의 명령어(예: `pnpm add`, `yarn add`)로 바꾸어 주세요.</span>
130
+ <span lang="ko">npm이 아닌 다른 패키지 매니저를 사용하는 경우 `npm install`을 해당 패키지 매니저의 명령어(예: `pnpm add`, `yarn add`)로 바꿔 주세요.</span>
131
131
 
132
132
  ## Usage / <span lang="ja">使い方</span> / <span lang="zh-Hans-CN">用法</span> / <span lang="ko">사용법</span>
133
133
 
@@ -137,7 +137,7 @@ Import `micromark` and `micromark-extension-cjk-friendly`, and use the extension
137
137
 
138
138
  <span lang="zh-Hans-CN">通过 `micromark` 和 `micromark-extension-cjk-friendly` 导入,然后使用扩展如下:</span>
139
139
 
140
- <span lang="ko">`micromark`와 `micromark-extension-cjk-friendly`를 임포트하고 다음과 같이 확장을 사용하세요.</span>
140
+ <span lang="ko">`micromark`와 `micromark-extension-cjk-friendly`를 가져오고 다음과 같이 확장을 사용하세요.</span>
141
141
 
142
142
  ```js
143
143
  import { micromark } from "micromark";
@@ -162,9 +162,9 @@ This modification of the specification does not affect the other languages than
162
162
 
163
163
  <span lang="zh-Hans-CN">除中文、日文和韩文外,建议的规范变更不会影响其他语言。请放心使用此软件包,因为如果您的应用程序或文档包含其他语言的翻译或内容,也不会受到影响。我保证,即使使用此软件包(修正建议),micromark 仍然会为 0.31.2 版本的所有 CommonMark 测试用例输出相同的 HTML。</span>
164
164
 
165
- <span lang="ko">이번 사양 변경 제안은 한국어, 중국어, 일본어 이외의 언어에는 영향을 미치지 않습니다. 애플리케이션이나 문서에 다른 언어의 번역이나 콘텐츠가 포함되어 있어도 영향을 받지 않으므로 안심하고 본 패키지를 사용하시기 바랍니다. 본 패키지(수정안)를 사용해도 0.31.2 시점의 모든 CommonMark 테스트케이스에서 micromark가 동일한 HTML을 출력하는 것을 보장합니다.</span>
165
+ <span lang="ko">이 사양 변경 제안은 한국어, 일본어, 중국어 이외의 언어에는 영향을 미치지 않습니다. 애플리케이션이나 문서에 다른 언어의 번역이나 콘텐츠가 포함되어 있어도 영향을 받지 않으므로 안심하고 본 패키지를 사용하시기 바랍니다. 본 패키지(수정안)를 사용해도 0.31.2 시점의 모든 CommonMark 테스트 케이스에서 micromark가 동일한 HTML을 출력하는 것을 보장합니다.</span>
166
166
 
167
- ## Specification / <span lang="ja">規格書</span> / <span lang="zh-Hans-CN">规范</span> / <span lang="ko">규정서</span>
167
+ ## Specification / <span lang="ja">規格書</span> / <span lang="zh-Hans-CN">规范</span> / <span lang="ko">설명서</span>
168
168
 
169
169
  https://github.com/tats-u/markdown-cjk-friendly/blob/main/specification.md (English)
170
170
 
@@ -1,5 +1,6 @@
1
- import { Construct } from 'micromark-util-types';
1
+ import { Construct } from "micromark-util-types";
2
2
 
3
+ //#region src/ext/attention.d.ts
3
4
  declare const attention: Construct;
4
-
5
- export { attention };
5
+ //#endregion
6
+ export { attention };
@@ -1,183 +1,212 @@
1
- // src/ext/attention.ts
2
- import { ok as assert } from "devlop";
3
- import {
4
- classifyCharacter,
5
- classifyPrecedingCharacter,
6
- isCjk,
7
- isCjkOrIvs,
8
- isCodeHighSurrogate,
9
- isCodeLowSurrogate,
10
- isNonCjkPunctuation,
11
- isSpaceOrPunctuation,
12
- isUnicodeWhitespace,
13
- TwoPreviousCode,
14
- tryGetGenuineNextCode,
15
- tryGetGenuinePreviousCode
16
- } from "micromark-extension-cjk-friendly-util";
1
+ import { codes, types } from "micromark-util-symbol";
2
+ import { ok } from "devlop";
3
+ import { TwoPreviousCode, classifyCharacter, classifyPrecedingCharacter, isCjk, isCjkOrIvs, isCodeHighSurrogate, isCodeLowSurrogate, isNonCjkPunctuation, isSpaceOrPunctuation, isUnicodeWhitespace, tryGetGenuineNextCode, tryGetGenuinePreviousCode } from "micromark-extension-cjk-friendly-util";
17
4
  import { push, splice } from "micromark-util-chunked";
18
5
  import { resolveAll } from "micromark-util-resolve-all";
19
- import { codes, types } from "micromark-util-symbol";
20
- var attention = {
21
- name: "attention",
22
- resolveAll: resolveAllAttention,
23
- tokenize: tokenizeAttention
6
+
7
+ //#region src/ext/attention.ts
8
+ const attention = {
9
+ name: "attention",
10
+ resolveAll: resolveAllAttention,
11
+ tokenize: tokenizeAttention
24
12
  };
25
13
  function resolveAllAttention(events, context) {
26
- let index = -1;
27
- let open;
28
- let group;
29
- let text;
30
- let openingSequence;
31
- let closingSequence;
32
- let use;
33
- let nextEvents;
34
- let offset;
35
- while (++index < events.length) {
36
- if (events[index][0] === "enter" && events[index][1].type === "attentionSequence" && events[index][1]._close) {
37
- open = index;
38
- while (open--) {
39
- if (events[open][0] === "exit" && events[open][1].type === "attentionSequence" && events[open][1]._open && // If the markers are the same:
40
- context.sliceSerialize(events[open][1]).charCodeAt(0) === context.sliceSerialize(events[index][1]).charCodeAt(0)) {
41
- if ((events[open][1]._close || events[index][1]._open) && (events[index][1].end.offset - events[index][1].start.offset) % 3 && !((events[open][1].end.offset - events[open][1].start.offset + events[index][1].end.offset - events[index][1].start.offset) % 3)) {
42
- continue;
43
- }
44
- use = events[open][1].end.offset - events[open][1].start.offset > 1 && events[index][1].end.offset - events[index][1].start.offset > 1 ? 2 : 1;
45
- const start = { ...events[open][1].end };
46
- const end = { ...events[index][1].start };
47
- movePoint(start, -use);
48
- movePoint(end, use);
49
- openingSequence = {
50
- type: use > 1 ? types.strongSequence : types.emphasisSequence,
51
- start,
52
- end: { ...events[open][1].end }
53
- };
54
- closingSequence = {
55
- type: use > 1 ? types.strongSequence : types.emphasisSequence,
56
- start: { ...events[index][1].start },
57
- end
58
- };
59
- text = {
60
- type: use > 1 ? types.strongText : types.emphasisText,
61
- start: { ...events[open][1].end },
62
- end: { ...events[index][1].start }
63
- };
64
- group = {
65
- type: use > 1 ? types.strong : types.emphasis,
66
- start: { ...openingSequence.start },
67
- end: { ...closingSequence.end }
68
- };
69
- events[open][1].end = { ...openingSequence.start };
70
- events[index][1].start = { ...closingSequence.end };
71
- nextEvents = [];
72
- if (events[open][1].end.offset - events[open][1].start.offset) {
73
- nextEvents = push(nextEvents, [
74
- ["enter", events[open][1], context],
75
- ["exit", events[open][1], context]
76
- ]);
77
- }
78
- nextEvents = push(nextEvents, [
79
- ["enter", group, context],
80
- ["enter", openingSequence, context],
81
- ["exit", openingSequence, context],
82
- ["enter", text, context]
83
- ]);
84
- assert(
85
- context.parser.constructs.insideSpan.null,
86
- "expected `insideSpan` to be populated"
87
- );
88
- nextEvents = push(
89
- nextEvents,
90
- resolveAll(
91
- context.parser.constructs.insideSpan.null,
92
- events.slice(open + 1, index),
93
- context
94
- )
95
- );
96
- nextEvents = push(nextEvents, [
97
- ["exit", text, context],
98
- ["enter", closingSequence, context],
99
- ["exit", closingSequence, context],
100
- ["exit", group, context]
101
- ]);
102
- if (events[index][1].end.offset - events[index][1].start.offset) {
103
- offset = 2;
104
- nextEvents = push(nextEvents, [
105
- ["enter", events[index][1], context],
106
- ["exit", events[index][1], context]
107
- ]);
108
- } else {
109
- offset = 0;
110
- }
111
- splice(events, open - 1, index - open + 3, nextEvents);
112
- index = open + nextEvents.length - offset - 2;
113
- break;
114
- }
115
- }
116
- }
117
- }
118
- index = -1;
119
- while (++index < events.length) {
120
- if (events[index][1].type === "attentionSequence") {
121
- events[index][1].type = "data";
122
- }
123
- }
124
- return events;
14
+ let index = -1;
15
+ let open;
16
+ let group;
17
+ let text;
18
+ let openingSequence;
19
+ let closingSequence;
20
+ let use;
21
+ let nextEvents;
22
+ let offset;
23
+ while (++index < events.length) if (events[index][0] === "enter" && events[index][1].type === "attentionSequence" && events[index][1]._close) {
24
+ open = index;
25
+ while (open--) if (events[open][0] === "exit" && events[open][1].type === "attentionSequence" && events[open][1]._open && context.sliceSerialize(events[open][1]).charCodeAt(0) === context.sliceSerialize(events[index][1]).charCodeAt(0)) {
26
+ if ((events[open][1]._close || events[index][1]._open) && (events[index][1].end.offset - events[index][1].start.offset) % 3 && !((events[open][1].end.offset - events[open][1].start.offset + events[index][1].end.offset - events[index][1].start.offset) % 3)) continue;
27
+ use = events[open][1].end.offset - events[open][1].start.offset > 1 && events[index][1].end.offset - events[index][1].start.offset > 1 ? 2 : 1;
28
+ const start = { ...events[open][1].end };
29
+ const end = { ...events[index][1].start };
30
+ movePoint(start, -use);
31
+ movePoint(end, use);
32
+ openingSequence = {
33
+ type: use > 1 ? types.strongSequence : types.emphasisSequence,
34
+ start,
35
+ end: { ...events[open][1].end }
36
+ };
37
+ closingSequence = {
38
+ type: use > 1 ? types.strongSequence : types.emphasisSequence,
39
+ start: { ...events[index][1].start },
40
+ end
41
+ };
42
+ text = {
43
+ type: use > 1 ? types.strongText : types.emphasisText,
44
+ start: { ...events[open][1].end },
45
+ end: { ...events[index][1].start }
46
+ };
47
+ group = {
48
+ type: use > 1 ? types.strong : types.emphasis,
49
+ start: { ...openingSequence.start },
50
+ end: { ...closingSequence.end }
51
+ };
52
+ events[open][1].end = { ...openingSequence.start };
53
+ events[index][1].start = { ...closingSequence.end };
54
+ nextEvents = [];
55
+ if (events[open][1].end.offset - events[open][1].start.offset) nextEvents = push(nextEvents, [[
56
+ "enter",
57
+ events[open][1],
58
+ context
59
+ ], [
60
+ "exit",
61
+ events[open][1],
62
+ context
63
+ ]]);
64
+ nextEvents = push(nextEvents, [
65
+ [
66
+ "enter",
67
+ group,
68
+ context
69
+ ],
70
+ [
71
+ "enter",
72
+ openingSequence,
73
+ context
74
+ ],
75
+ [
76
+ "exit",
77
+ openingSequence,
78
+ context
79
+ ],
80
+ [
81
+ "enter",
82
+ text,
83
+ context
84
+ ]
85
+ ]);
86
+ ok(context.parser.constructs.insideSpan.null, "expected `insideSpan` to be populated");
87
+ nextEvents = push(nextEvents, resolveAll(context.parser.constructs.insideSpan.null, events.slice(open + 1, index), context));
88
+ nextEvents = push(nextEvents, [
89
+ [
90
+ "exit",
91
+ text,
92
+ context
93
+ ],
94
+ [
95
+ "enter",
96
+ closingSequence,
97
+ context
98
+ ],
99
+ [
100
+ "exit",
101
+ closingSequence,
102
+ context
103
+ ],
104
+ [
105
+ "exit",
106
+ group,
107
+ context
108
+ ]
109
+ ]);
110
+ if (events[index][1].end.offset - events[index][1].start.offset) {
111
+ offset = 2;
112
+ nextEvents = push(nextEvents, [[
113
+ "enter",
114
+ events[index][1],
115
+ context
116
+ ], [
117
+ "exit",
118
+ events[index][1],
119
+ context
120
+ ]]);
121
+ } else offset = 0;
122
+ splice(events, open - 1, index - open + 3, nextEvents);
123
+ index = open + nextEvents.length - offset - 2;
124
+ break;
125
+ }
126
+ }
127
+ index = -1;
128
+ while (++index < events.length) if (events[index][1].type === "attentionSequence") events[index][1].type = "data";
129
+ return events;
125
130
  }
126
- function tokenizeAttention(effects, ok) {
127
- const attentionMarkers = this.parser.constructs.attentionMarkers.null;
128
- const { now, sliceSerialize, previous: tentativePrevious } = this;
129
- const previous = isCodeLowSurrogate(tentativePrevious) ? (
130
- // second (lower) surrogate likely to be preceded by first (higher) surrogate
131
- tryGetGenuinePreviousCode(tentativePrevious, now(), sliceSerialize)
132
- ) : tentativePrevious;
133
- const before = classifyCharacter(previous);
134
- const twoPrevious = new TwoPreviousCode(previous, now(), sliceSerialize);
135
- const beforePrimary = classifyPrecedingCharacter(
136
- before,
137
- twoPrevious.value.bind(twoPrevious),
138
- previous
139
- );
140
- let marker;
141
- return start;
142
- function start(code) {
143
- assert(
144
- code === codes.asterisk || code === codes.underscore,
145
- "expected asterisk or underscore"
146
- );
147
- marker = code;
148
- effects.enter("attentionSequence");
149
- return inside(code);
150
- }
151
- function inside(code) {
152
- if (code === marker) {
153
- effects.consume(code);
154
- return inside;
155
- }
156
- const token = effects.exit("attentionSequence");
157
- const next = isCodeHighSurrogate(code) ? tryGetGenuineNextCode(code, now(), sliceSerialize) : code;
158
- const after = classifyCharacter(next);
159
- assert(attentionMarkers, "expected `attentionMarkers` to be populated");
160
- const beforeNonCjkPunctuation = isNonCjkPunctuation(beforePrimary);
161
- const beforeSpaceOrNonCjkPunctuation = beforeNonCjkPunctuation || isUnicodeWhitespace(beforePrimary);
162
- const afterNonCjkPunctuation = isNonCjkPunctuation(after);
163
- const afterSpaceOrNonCjkPunctuation = afterNonCjkPunctuation || isUnicodeWhitespace(after);
164
- const beforeCjkOrIvs = isCjkOrIvs(beforePrimary);
165
- const open = !afterSpaceOrNonCjkPunctuation || afterNonCjkPunctuation && (beforeSpaceOrNonCjkPunctuation || beforeCjkOrIvs) || attentionMarkers.includes(code);
166
- const close = !beforeSpaceOrNonCjkPunctuation || beforeNonCjkPunctuation && (afterSpaceOrNonCjkPunctuation || isCjk(after)) || attentionMarkers.includes(previous);
167
- token._open = Boolean(
168
- marker === codes.asterisk ? open : open && (isSpaceOrPunctuation(beforePrimary) || !close)
169
- );
170
- token._close = Boolean(
171
- marker === codes.asterisk ? close : close && (isSpaceOrPunctuation(after) || !open)
172
- );
173
- return ok(code);
174
- }
131
+ /**
132
+ * @this {TokenizeContext}
133
+ * Context.
134
+ * @type {Tokenizer}
135
+ */
136
+ function tokenizeAttention(effects, ok$1) {
137
+ const attentionMarkers = this.parser.constructs.attentionMarkers.null;
138
+ const { now, sliceSerialize, previous: tentativePrevious } = this;
139
+ const previous = isCodeLowSurrogate(tentativePrevious) ? tryGetGenuinePreviousCode(tentativePrevious, now(), sliceSerialize) : tentativePrevious;
140
+ const before = classifyCharacter(previous);
141
+ const twoPrevious = new TwoPreviousCode(previous, now(), sliceSerialize);
142
+ const beforePrimary = classifyPrecedingCharacter(before, twoPrevious.value.bind(twoPrevious), previous);
143
+ /** @type {NonNullable<Code>} */
144
+ let marker;
145
+ return start;
146
+ /**
147
+ * Before a sequence.
148
+ *
149
+ * ```markdown
150
+ * > | **
151
+ * ^
152
+ * ```
153
+ *
154
+ * @type {State}
155
+ */
156
+ function start(code) {
157
+ ok(code === codes.asterisk || code === codes.underscore, "expected asterisk or underscore");
158
+ marker = code;
159
+ effects.enter("attentionSequence");
160
+ return inside(code);
161
+ }
162
+ /**
163
+ * In a sequence.
164
+ *
165
+ * ```markdown
166
+ * > | **
167
+ * ^^
168
+ * ```
169
+ *
170
+ * @type {State}
171
+ */
172
+ function inside(code) {
173
+ if (code === marker) {
174
+ effects.consume(code);
175
+ return inside;
176
+ }
177
+ const token = effects.exit("attentionSequence");
178
+ const after = classifyCharacter(isCodeHighSurrogate(code) ? tryGetGenuineNextCode(code, now(), sliceSerialize) : code);
179
+ ok(attentionMarkers, "expected `attentionMarkers` to be populated");
180
+ const beforeNonCjkPunctuation = isNonCjkPunctuation(beforePrimary);
181
+ const beforeSpaceOrNonCjkPunctuation = beforeNonCjkPunctuation || isUnicodeWhitespace(beforePrimary);
182
+ const afterNonCjkPunctuation = isNonCjkPunctuation(after);
183
+ const afterSpaceOrNonCjkPunctuation = afterNonCjkPunctuation || isUnicodeWhitespace(after);
184
+ const beforeCjkOrIvs = isCjkOrIvs(beforePrimary);
185
+ const open = !afterSpaceOrNonCjkPunctuation || afterNonCjkPunctuation && (beforeSpaceOrNonCjkPunctuation || beforeCjkOrIvs) || attentionMarkers.includes(code);
186
+ const close = !beforeSpaceOrNonCjkPunctuation || beforeNonCjkPunctuation && (afterSpaceOrNonCjkPunctuation || isCjk(after)) || attentionMarkers.includes(previous);
187
+ token._open = Boolean(marker === codes.asterisk ? open : open && (isSpaceOrPunctuation(beforePrimary) || !close));
188
+ token._close = Boolean(marker === codes.asterisk ? close : close && (isSpaceOrPunctuation(after) || !open));
189
+ return ok$1(code);
190
+ }
175
191
  }
192
+ /**
193
+ * Move a point a bit.
194
+ *
195
+ * Note: `move` only works inside lines! It’s not possible to move past other
196
+ * chunks (replacement characters, tabs, or line endings).
197
+ *
198
+ * @param {Point} point
199
+ * Point.
200
+ * @param {number} offset
201
+ * Amount to move.
202
+ * @returns {undefined}
203
+ * Nothing.
204
+ */
176
205
  function movePoint(point, offset) {
177
- point.column += offset;
178
- point.offset += offset;
179
- point._bufferIndex += offset;
206
+ point.column += offset;
207
+ point.offset += offset;
208
+ point._bufferIndex += offset;
180
209
  }
181
- export {
182
- attention
183
- };
210
+
211
+ //#endregion
212
+ export { attention };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,10 @@
1
- import { Extension } from 'micromark-util-types';
1
+ import { Extension } from "micromark-util-types";
2
+
3
+ //#region src/index.d.ts
2
4
 
3
5
  /**
4
6
  * Make Markdown emphasis (`**`) in CommonMark more friendly with Chinese, Japanese, and Korean (CJK).
5
7
  */
6
8
  declare function cjkFriendlyExtension(): Extension;
7
-
8
- export { cjkFriendlyExtension };
9
+ //#endregion
10
+ export { cjkFriendlyExtension };
package/dist/index.js CHANGED
@@ -1,197 +1,19 @@
1
- // src/index.ts
2
- import { codes as codes2 } from "micromark-util-symbol";
1
+ import { attention } from "./ext/attention.js";
2
+ import { codes } from "micromark-util-symbol";
3
3
 
4
- // src/ext/attention.ts
5
- import { ok as assert } from "devlop";
6
- import {
7
- classifyCharacter,
8
- classifyPrecedingCharacter,
9
- isCjk,
10
- isCjkOrIvs,
11
- isCodeHighSurrogate,
12
- isCodeLowSurrogate,
13
- isNonCjkPunctuation,
14
- isSpaceOrPunctuation,
15
- isUnicodeWhitespace,
16
- TwoPreviousCode,
17
- tryGetGenuineNextCode,
18
- tryGetGenuinePreviousCode
19
- } from "micromark-extension-cjk-friendly-util";
20
- import { push, splice } from "micromark-util-chunked";
21
- import { resolveAll } from "micromark-util-resolve-all";
22
- import { codes, types } from "micromark-util-symbol";
23
- var attention = {
24
- name: "attention",
25
- resolveAll: resolveAllAttention,
26
- tokenize: tokenizeAttention
27
- };
28
- function resolveAllAttention(events, context) {
29
- let index = -1;
30
- let open;
31
- let group;
32
- let text;
33
- let openingSequence;
34
- let closingSequence;
35
- let use;
36
- let nextEvents;
37
- let offset;
38
- while (++index < events.length) {
39
- if (events[index][0] === "enter" && events[index][1].type === "attentionSequence" && events[index][1]._close) {
40
- open = index;
41
- while (open--) {
42
- if (events[open][0] === "exit" && events[open][1].type === "attentionSequence" && events[open][1]._open && // If the markers are the same:
43
- context.sliceSerialize(events[open][1]).charCodeAt(0) === context.sliceSerialize(events[index][1]).charCodeAt(0)) {
44
- if ((events[open][1]._close || events[index][1]._open) && (events[index][1].end.offset - events[index][1].start.offset) % 3 && !((events[open][1].end.offset - events[open][1].start.offset + events[index][1].end.offset - events[index][1].start.offset) % 3)) {
45
- continue;
46
- }
47
- use = events[open][1].end.offset - events[open][1].start.offset > 1 && events[index][1].end.offset - events[index][1].start.offset > 1 ? 2 : 1;
48
- const start = { ...events[open][1].end };
49
- const end = { ...events[index][1].start };
50
- movePoint(start, -use);
51
- movePoint(end, use);
52
- openingSequence = {
53
- type: use > 1 ? types.strongSequence : types.emphasisSequence,
54
- start,
55
- end: { ...events[open][1].end }
56
- };
57
- closingSequence = {
58
- type: use > 1 ? types.strongSequence : types.emphasisSequence,
59
- start: { ...events[index][1].start },
60
- end
61
- };
62
- text = {
63
- type: use > 1 ? types.strongText : types.emphasisText,
64
- start: { ...events[open][1].end },
65
- end: { ...events[index][1].start }
66
- };
67
- group = {
68
- type: use > 1 ? types.strong : types.emphasis,
69
- start: { ...openingSequence.start },
70
- end: { ...closingSequence.end }
71
- };
72
- events[open][1].end = { ...openingSequence.start };
73
- events[index][1].start = { ...closingSequence.end };
74
- nextEvents = [];
75
- if (events[open][1].end.offset - events[open][1].start.offset) {
76
- nextEvents = push(nextEvents, [
77
- ["enter", events[open][1], context],
78
- ["exit", events[open][1], context]
79
- ]);
80
- }
81
- nextEvents = push(nextEvents, [
82
- ["enter", group, context],
83
- ["enter", openingSequence, context],
84
- ["exit", openingSequence, context],
85
- ["enter", text, context]
86
- ]);
87
- assert(
88
- context.parser.constructs.insideSpan.null,
89
- "expected `insideSpan` to be populated"
90
- );
91
- nextEvents = push(
92
- nextEvents,
93
- resolveAll(
94
- context.parser.constructs.insideSpan.null,
95
- events.slice(open + 1, index),
96
- context
97
- )
98
- );
99
- nextEvents = push(nextEvents, [
100
- ["exit", text, context],
101
- ["enter", closingSequence, context],
102
- ["exit", closingSequence, context],
103
- ["exit", group, context]
104
- ]);
105
- if (events[index][1].end.offset - events[index][1].start.offset) {
106
- offset = 2;
107
- nextEvents = push(nextEvents, [
108
- ["enter", events[index][1], context],
109
- ["exit", events[index][1], context]
110
- ]);
111
- } else {
112
- offset = 0;
113
- }
114
- splice(events, open - 1, index - open + 3, nextEvents);
115
- index = open + nextEvents.length - offset - 2;
116
- break;
117
- }
118
- }
119
- }
120
- }
121
- index = -1;
122
- while (++index < events.length) {
123
- if (events[index][1].type === "attentionSequence") {
124
- events[index][1].type = "data";
125
- }
126
- }
127
- return events;
128
- }
129
- function tokenizeAttention(effects, ok) {
130
- const attentionMarkers = this.parser.constructs.attentionMarkers.null;
131
- const { now, sliceSerialize, previous: tentativePrevious } = this;
132
- const previous = isCodeLowSurrogate(tentativePrevious) ? (
133
- // second (lower) surrogate likely to be preceded by first (higher) surrogate
134
- tryGetGenuinePreviousCode(tentativePrevious, now(), sliceSerialize)
135
- ) : tentativePrevious;
136
- const before = classifyCharacter(previous);
137
- const twoPrevious = new TwoPreviousCode(previous, now(), sliceSerialize);
138
- const beforePrimary = classifyPrecedingCharacter(
139
- before,
140
- twoPrevious.value.bind(twoPrevious),
141
- previous
142
- );
143
- let marker;
144
- return start;
145
- function start(code) {
146
- assert(
147
- code === codes.asterisk || code === codes.underscore,
148
- "expected asterisk or underscore"
149
- );
150
- marker = code;
151
- effects.enter("attentionSequence");
152
- return inside(code);
153
- }
154
- function inside(code) {
155
- if (code === marker) {
156
- effects.consume(code);
157
- return inside;
158
- }
159
- const token = effects.exit("attentionSequence");
160
- const next = isCodeHighSurrogate(code) ? tryGetGenuineNextCode(code, now(), sliceSerialize) : code;
161
- const after = classifyCharacter(next);
162
- assert(attentionMarkers, "expected `attentionMarkers` to be populated");
163
- const beforeNonCjkPunctuation = isNonCjkPunctuation(beforePrimary);
164
- const beforeSpaceOrNonCjkPunctuation = beforeNonCjkPunctuation || isUnicodeWhitespace(beforePrimary);
165
- const afterNonCjkPunctuation = isNonCjkPunctuation(after);
166
- const afterSpaceOrNonCjkPunctuation = afterNonCjkPunctuation || isUnicodeWhitespace(after);
167
- const beforeCjkOrIvs = isCjkOrIvs(beforePrimary);
168
- const open = !afterSpaceOrNonCjkPunctuation || afterNonCjkPunctuation && (beforeSpaceOrNonCjkPunctuation || beforeCjkOrIvs) || attentionMarkers.includes(code);
169
- const close = !beforeSpaceOrNonCjkPunctuation || beforeNonCjkPunctuation && (afterSpaceOrNonCjkPunctuation || isCjk(after)) || attentionMarkers.includes(previous);
170
- token._open = Boolean(
171
- marker === codes.asterisk ? open : open && (isSpaceOrPunctuation(beforePrimary) || !close)
172
- );
173
- token._close = Boolean(
174
- marker === codes.asterisk ? close : close && (isSpaceOrPunctuation(after) || !open)
175
- );
176
- return ok(code);
177
- }
178
- }
179
- function movePoint(point, offset) {
180
- point.column += offset;
181
- point.offset += offset;
182
- point._bufferIndex += offset;
183
- }
184
-
185
- // src/index.ts
4
+ //#region src/index.ts
5
+ /**
6
+ * Make Markdown emphasis (`**`) in CommonMark more friendly with Chinese, Japanese, and Korean (CJK).
7
+ */
186
8
  function cjkFriendlyExtension() {
187
- return {
188
- text: {
189
- [codes2.asterisk]: attention,
190
- [codes2.underscore]: attention
191
- },
192
- insideSpan: { null: [attention] }
193
- };
9
+ return {
10
+ text: {
11
+ [codes.asterisk]: attention,
12
+ [codes.underscore]: attention
13
+ },
14
+ insideSpan: { null: [attention] }
15
+ };
194
16
  }
195
- export {
196
- cjkFriendlyExtension
197
- };
17
+
18
+ //#endregion
19
+ export { cjkFriendlyExtension };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "micromark-extension-cjk-friendly",
3
- "version": "1.2.3",
3
+ "version": "2.0.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -37,7 +37,7 @@
37
37
  "micromark-util-chunked": "^2.0.1",
38
38
  "micromark-util-resolve-all": "^2.0.1",
39
39
  "micromark-util-symbol": "^2.0.1",
40
- "micromark-extension-cjk-friendly-util": "2.1.1"
40
+ "micromark-extension-cjk-friendly-util": "3.0.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "micromark": "^4.0.2",
@@ -54,15 +54,13 @@
54
54
  }
55
55
  },
56
56
  "engines": {
57
- "node": ">=16"
57
+ "node": ">=18"
58
58
  },
59
59
  "scripts": {
60
- "build:rslib": "rslib build",
61
- "build": "tsup",
62
- "build:lib": "tsup",
63
- "dev:rslib": "rslib build --watch",
64
- "dev": "tsup --watch",
65
- "dev:lib": "tsup --watch",
60
+ "build": "tsdown",
61
+ "build:lib": "tsdown",
62
+ "dev": "tsdown --watch",
63
+ "dev:lib": "tsdown --watch",
66
64
  "test": "vitest run",
67
65
  "test:lib": "vitest run",
68
66
  "test:up": "vitest -u",