@cosense-toolbox/parser 0.1.0-beta.1 → 0.1.0-beta.3

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.
Files changed (76) hide show
  1. package/README.md +45 -31
  2. package/dist/{ast-uYWtkHwT.cjs → ast-C0BGz7X2.cjs} +2 -2
  3. package/dist/ast-C0BGz7X2.cjs.map +1 -0
  4. package/dist/{ast-CIKXwSl5.mjs → ast-CMQYawYl.mjs} +2 -2
  5. package/dist/ast-CMQYawYl.mjs.map +1 -0
  6. package/dist/compile.cjs +2 -213
  7. package/dist/compile.cjs.map +1 -1
  8. package/dist/compile.d.cts +2 -129
  9. package/dist/compile.d.cts.map +1 -1
  10. package/dist/compile.d.mts +2 -129
  11. package/dist/compile.d.mts.map +1 -1
  12. package/dist/compile.mjs +3 -207
  13. package/dist/compile.mjs.map +1 -1
  14. package/dist/extensions.cjs +10 -7
  15. package/dist/extensions.cjs.map +1 -1
  16. package/dist/extensions.d.cts +12 -8
  17. package/dist/extensions.d.cts.map +1 -1
  18. package/dist/extensions.d.mts +12 -8
  19. package/dist/extensions.d.mts.map +1 -1
  20. package/dist/extensions.mjs +10 -7
  21. package/dist/extensions.mjs.map +1 -1
  22. package/dist/html.cjs +458 -0
  23. package/dist/html.cjs.map +1 -0
  24. package/dist/html.d.cts +274 -0
  25. package/dist/html.d.cts.map +1 -0
  26. package/dist/html.d.mts +274 -0
  27. package/dist/html.d.mts.map +1 -0
  28. package/dist/html.mjs +447 -0
  29. package/dist/html.mjs.map +1 -0
  30. package/dist/image-url-YcTed8tg.cjs.map +1 -1
  31. package/dist/image-url-eQ6X-oN0.mjs.map +1 -1
  32. package/dist/index-CrIlOW1k.d.mts +78 -0
  33. package/dist/index-CrIlOW1k.d.mts.map +1 -0
  34. package/dist/index-_o1STNhP.d.cts +78 -0
  35. package/dist/index-_o1STNhP.d.cts.map +1 -0
  36. package/dist/index.cjs +188 -35
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d.cts +4 -77
  39. package/dist/index.d.mts +4 -77
  40. package/dist/index.mjs +180 -27
  41. package/dist/index.mjs.map +1 -1
  42. package/dist/schema.cjs +1 -0
  43. package/dist/schema.cjs.map +1 -1
  44. package/dist/schema.d.cts +1 -1
  45. package/dist/schema.d.cts.map +1 -1
  46. package/dist/schema.d.mts +1 -1
  47. package/dist/schema.d.mts.map +1 -1
  48. package/dist/schema.mjs +1 -0
  49. package/dist/schema.mjs.map +1 -1
  50. package/dist/{types-CiwPj2R8.d.cts → types-CdiHju1P.d.mts} +15 -12
  51. package/dist/types-CdiHju1P.d.mts.map +1 -0
  52. package/dist/{types-9vAAFHka.d.mts → types-_-ZAyNkz.d.cts} +15 -12
  53. package/dist/types-_-ZAyNkz.d.cts.map +1 -0
  54. package/dist/{types-DmfFumcw.d.cts → types-gWMrsXPX.d.cts} +28 -21
  55. package/dist/{types-DmfFumcw.d.cts.map → types-gWMrsXPX.d.cts.map} +1 -1
  56. package/dist/{types-DmfFumcw.d.mts → types-gWMrsXPX.d.mts} +28 -21
  57. package/dist/{types-DmfFumcw.d.mts.map → types-gWMrsXPX.d.mts.map} +1 -1
  58. package/dist/utils.cjs +1 -1
  59. package/dist/utils.cjs.map +1 -1
  60. package/dist/utils.d.cts +2 -2
  61. package/dist/utils.d.cts.map +1 -1
  62. package/dist/utils.d.mts +2 -2
  63. package/dist/utils.d.mts.map +1 -1
  64. package/dist/utils.mjs +1 -1
  65. package/dist/utils.mjs.map +1 -1
  66. package/package.json +27 -5
  67. package/dist/ast-CIKXwSl5.mjs.map +0 -1
  68. package/dist/ast-uYWtkHwT.cjs.map +0 -1
  69. package/dist/decoration-DODaJKeA.cjs +0 -103
  70. package/dist/decoration-DODaJKeA.cjs.map +0 -1
  71. package/dist/decoration-Dq_5e20j.mjs +0 -68
  72. package/dist/decoration-Dq_5e20j.mjs.map +0 -1
  73. package/dist/index.d.cts.map +0 -1
  74. package/dist/index.d.mts.map +0 -1
  75. package/dist/types-9vAAFHka.d.mts.map +0 -1
  76. package/dist/types-CiwPj2R8.d.cts.map +0 -1
@@ -1,14 +1,17 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_decoration = require("./decoration-DODaJKeA.cjs");
3
- //#region src/extensions/custom-decoration.ts
2
+ //#region src/extensions/table-cell-notation.ts
4
3
  /**
5
- * 文字装飾記法として読む記号を増やす拡張。
4
+ * テーブルのセルの中でも、行と同じく記法を読む拡張。Cosense Web には無い振る舞い。
6
5
  *
7
- * 既定では `* / - _` の 4 つだけを装飾として読み、それ以外は内部リンクになる。
8
- * 渡した記号は既定の記号と混ぜられ、`[*' x]` は太字かつ `markers: ['*', "'"]` になる。
6
+ * 既定ではセルの中はリンクの記法だけを読み、それ以外は書いたままの文字になる (Cosense Web と同じ)。
7
+ * `types` を渡すと、リンクに加えてその型のノードだけを読む。省くとすべての記法 (拡張の記法も含む) を読む。
8
+ *
9
+ * @example
10
+ * parse(source, { extensions: [tableCellNotation()] }) // すべての記法
11
+ * parse(source, { extensions: [tableCellNotation(['decoration'])] }) // リンクと装飾だけ
9
12
  */
10
- const customDecorations = (markers) => ({ bracketRules: [require_decoration.buildDecorationRule(require_decoration.OFFICIAL_MARKERS + markers.join(""))] });
13
+ const tableCellNotation = (types) => ({ keepInTableCell: types === void 0 ? () => true : (node) => types.includes(node.type) });
11
14
  //#endregion
12
- exports.customDecorations = customDecorations;
15
+ exports.tableCellNotation = tableCellNotation;
13
16
 
14
17
  //# sourceMappingURL=extensions.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extensions.cjs","names":["buildDecorationRule","OFFICIAL_MARKERS"],"sources":["../src/extensions/custom-decoration.ts"],"sourcesContent":["import { OFFICIAL_MARKERS, buildDecorationRule } from '../inline/bracket-rules/decoration'\nimport type { Extension } from '../inline/types'\n\n/**\n * 文字装飾記法として読む記号を増やす拡張。\n *\n * 既定では `* / - _` の 4 つだけを装飾として読み、それ以外は内部リンクになる。\n * 渡した記号は既定の記号と混ぜられ、`[*' x]` は太字かつ `markers: ['*', \"'\"]` になる。\n */\nexport const customDecorations = (markers: readonly string[]): Extension => ({\n bracketRules: [buildDecorationRule(OFFICIAL_MARKERS + markers.join(''))],\n})\n"],"mappings":";;;;;;;;;AASA,MAAa,qBAAqB,aAA2C,EAC3E,cAAc,CAACA,mBAAAA,oBAAoBC,mBAAAA,mBAAmB,QAAQ,KAAK,EAAE,CAAC,CAAC,EACzE"}
1
+ {"version":3,"file":"extensions.cjs","names":[],"sources":["../src/extensions/table-cell-notation.ts"],"sourcesContent":["import type { Extension } from \"../inline/types\"\nimport type { InlineNode } from \"../types\"\n\n/**\n * テーブルのセルの中でも、行と同じく記法を読む拡張。Cosense Web には無い振る舞い。\n *\n * 既定ではセルの中はリンクの記法だけを読み、それ以外は書いたままの文字になる (Cosense Web と同じ)。\n * `types` を渡すと、リンクに加えてその型のノードだけを読む。省くとすべての記法 (拡張の記法も含む) を読む。\n *\n * @example\n * parse(source, { extensions: [tableCellNotation()] }) // すべての記法\n * parse(source, { extensions: [tableCellNotation(['decoration'])] }) // リンクと装飾だけ\n */\nexport const tableCellNotation = (types?: readonly InlineNode[\"type\"][]): Extension => ({\n keepInTableCell: types === undefined ? () => true : (node) => types.includes(node.type),\n})\n"],"mappings":";;;;;;;;;;;;AAaA,MAAa,qBAAqB,WAAsD,EACtF,iBAAiB,UAAU,KAAA,UAAkB,QAAQ,SAAS,MAAM,SAAS,KAAK,IAAI,EACxF"}
@@ -1,13 +1,17 @@
1
- import { F as WithoutPosition, _ as InlineNodeInit } from "./types-DmfFumcw.cjs";
2
- import { a as InlineConstruct, i as Extension, n as BracketRuleContext, o as InlineContext, r as ConstructMatch, s as Origin, t as BracketRule } from "./types-CiwPj2R8.cjs";
3
- //#region src/extensions/custom-decoration.d.ts
1
+ import { F as WithoutPosition, _ as InlineNodeInit, g as InlineNode } from "./types-gWMrsXPX.cjs";
2
+ import { a as InlineConstruct, i as Extension, n as BracketRuleContext, o as InlineContext, r as ConstructMatch, s as Origin, t as BracketRule } from "./types-_-ZAyNkz.cjs";
3
+ //#region src/extensions/table-cell-notation.d.ts
4
4
  /**
5
- * 文字装飾記法として読む記号を増やす拡張。
5
+ * テーブルのセルの中でも、行と同じく記法を読む拡張。Cosense Web には無い振る舞い。
6
6
  *
7
- * 既定では `* / - _` の 4 つだけを装飾として読み、それ以外は内部リンクになる。
8
- * 渡した記号は既定の記号と混ぜられ、`[*' x]` は太字かつ `markers: ['*', "'"]` になる。
7
+ * 既定ではセルの中はリンクの記法だけを読み、それ以外は書いたままの文字になる (Cosense Web と同じ)。
8
+ * `types` を渡すと、リンクに加えてその型のノードだけを読む。省くとすべての記法 (拡張の記法も含む) を読む。
9
+ *
10
+ * @example
11
+ * parse(source, { extensions: [tableCellNotation()] }) // すべての記法
12
+ * parse(source, { extensions: [tableCellNotation(['decoration'])] }) // リンクと装飾だけ
9
13
  */
10
- declare const customDecorations: (markers: readonly string[]) => Extension;
14
+ declare const tableCellNotation: (types?: readonly InlineNode["type"][]) => Extension;
11
15
  //#endregion
12
- export { type BracketRule, type BracketRuleContext, type ConstructMatch, type Extension, type InlineConstruct, type InlineContext, type InlineNodeInit, type Origin, type WithoutPosition, customDecorations };
16
+ export { type BracketRule, type BracketRuleContext, type ConstructMatch, type Extension, type InlineConstruct, type InlineContext, type InlineNodeInit, type Origin, type WithoutPosition, tableCellNotation };
13
17
  //# sourceMappingURL=extensions.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extensions.d.cts","names":[],"sources":["../src/extensions/custom-decoration.ts"],"mappings":";;;;;;;;;cASa,oBAAqB,+BAA6B"}
1
+ {"version":3,"file":"extensions.d.cts","names":[],"sources":["../src/extensions/table-cell-notation.ts"],"mappings":";;;;;;;;;;;;;cAaa,oBAAqB,iBAAiB,yBAAuB"}
@@ -1,13 +1,17 @@
1
- import { F as WithoutPosition, _ as InlineNodeInit } from "./types-DmfFumcw.mjs";
2
- import { a as InlineConstruct, i as Extension, n as BracketRuleContext, o as InlineContext, r as ConstructMatch, s as Origin, t as BracketRule } from "./types-9vAAFHka.mjs";
3
- //#region src/extensions/custom-decoration.d.ts
1
+ import { F as WithoutPosition, _ as InlineNodeInit, g as InlineNode } from "./types-gWMrsXPX.mjs";
2
+ import { a as InlineConstruct, i as Extension, n as BracketRuleContext, o as InlineContext, r as ConstructMatch, s as Origin, t as BracketRule } from "./types-CdiHju1P.mjs";
3
+ //#region src/extensions/table-cell-notation.d.ts
4
4
  /**
5
- * 文字装飾記法として読む記号を増やす拡張。
5
+ * テーブルのセルの中でも、行と同じく記法を読む拡張。Cosense Web には無い振る舞い。
6
6
  *
7
- * 既定では `* / - _` の 4 つだけを装飾として読み、それ以外は内部リンクになる。
8
- * 渡した記号は既定の記号と混ぜられ、`[*' x]` は太字かつ `markers: ['*', "'"]` になる。
7
+ * 既定ではセルの中はリンクの記法だけを読み、それ以外は書いたままの文字になる (Cosense Web と同じ)。
8
+ * `types` を渡すと、リンクに加えてその型のノードだけを読む。省くとすべての記法 (拡張の記法も含む) を読む。
9
+ *
10
+ * @example
11
+ * parse(source, { extensions: [tableCellNotation()] }) // すべての記法
12
+ * parse(source, { extensions: [tableCellNotation(['decoration'])] }) // リンクと装飾だけ
9
13
  */
10
- declare const customDecorations: (markers: readonly string[]) => Extension;
14
+ declare const tableCellNotation: (types?: readonly InlineNode["type"][]) => Extension;
11
15
  //#endregion
12
- export { type BracketRule, type BracketRuleContext, type ConstructMatch, type Extension, type InlineConstruct, type InlineContext, type InlineNodeInit, type Origin, type WithoutPosition, customDecorations };
16
+ export { type BracketRule, type BracketRuleContext, type ConstructMatch, type Extension, type InlineConstruct, type InlineContext, type InlineNodeInit, type Origin, type WithoutPosition, tableCellNotation };
13
17
  //# sourceMappingURL=extensions.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extensions.d.mts","names":[],"sources":["../src/extensions/custom-decoration.ts"],"mappings":";;;;;;;;;cASa,oBAAqB,+BAA6B"}
1
+ {"version":3,"file":"extensions.d.mts","names":[],"sources":["../src/extensions/table-cell-notation.ts"],"mappings":";;;;;;;;;;;;;cAaa,oBAAqB,iBAAiB,yBAAuB"}
@@ -1,13 +1,16 @@
1
- import { n as buildDecorationRule, t as OFFICIAL_MARKERS } from "./decoration-Dq_5e20j.mjs";
2
- //#region src/extensions/custom-decoration.ts
1
+ //#region src/extensions/table-cell-notation.ts
3
2
  /**
4
- * 文字装飾記法として読む記号を増やす拡張。
3
+ * テーブルのセルの中でも、行と同じく記法を読む拡張。Cosense Web には無い振る舞い。
5
4
  *
6
- * 既定では `* / - _` の 4 つだけを装飾として読み、それ以外は内部リンクになる。
7
- * 渡した記号は既定の記号と混ぜられ、`[*' x]` は太字かつ `markers: ['*', "'"]` になる。
5
+ * 既定ではセルの中はリンクの記法だけを読み、それ以外は書いたままの文字になる (Cosense Web と同じ)。
6
+ * `types` を渡すと、リンクに加えてその型のノードだけを読む。省くとすべての記法 (拡張の記法も含む) を読む。
7
+ *
8
+ * @example
9
+ * parse(source, { extensions: [tableCellNotation()] }) // すべての記法
10
+ * parse(source, { extensions: [tableCellNotation(['decoration'])] }) // リンクと装飾だけ
8
11
  */
9
- const customDecorations = (markers) => ({ bracketRules: [buildDecorationRule(OFFICIAL_MARKERS + markers.join(""))] });
12
+ const tableCellNotation = (types) => ({ keepInTableCell: types === void 0 ? () => true : (node) => types.includes(node.type) });
10
13
  //#endregion
11
- export { customDecorations };
14
+ export { tableCellNotation };
12
15
 
13
16
  //# sourceMappingURL=extensions.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extensions.mjs","names":[],"sources":["../src/extensions/custom-decoration.ts"],"sourcesContent":["import { OFFICIAL_MARKERS, buildDecorationRule } from '../inline/bracket-rules/decoration'\nimport type { Extension } from '../inline/types'\n\n/**\n * 文字装飾記法として読む記号を増やす拡張。\n *\n * 既定では `* / - _` の 4 つだけを装飾として読み、それ以外は内部リンクになる。\n * 渡した記号は既定の記号と混ぜられ、`[*' x]` は太字かつ `markers: ['*', \"'\"]` になる。\n */\nexport const customDecorations = (markers: readonly string[]): Extension => ({\n bracketRules: [buildDecorationRule(OFFICIAL_MARKERS + markers.join(''))],\n})\n"],"mappings":";;;;;;;;AASA,MAAa,qBAAqB,aAA2C,EAC3E,cAAc,CAAC,oBAAoB,mBAAmB,QAAQ,KAAK,EAAE,CAAC,CAAC,EACzE"}
1
+ {"version":3,"file":"extensions.mjs","names":[],"sources":["../src/extensions/table-cell-notation.ts"],"sourcesContent":["import type { Extension } from \"../inline/types\"\nimport type { InlineNode } from \"../types\"\n\n/**\n * テーブルのセルの中でも、行と同じく記法を読む拡張。Cosense Web には無い振る舞い。\n *\n * 既定ではセルの中はリンクの記法だけを読み、それ以外は書いたままの文字になる (Cosense Web と同じ)。\n * `types` を渡すと、リンクに加えてその型のノードだけを読む。省くとすべての記法 (拡張の記法も含む) を読む。\n *\n * @example\n * parse(source, { extensions: [tableCellNotation()] }) // すべての記法\n * parse(source, { extensions: [tableCellNotation(['decoration'])] }) // リンクと装飾だけ\n */\nexport const tableCellNotation = (types?: readonly InlineNode[\"type\"][]): Extension => ({\n keepInTableCell: types === undefined ? () => true : (node) => types.includes(node.type),\n})\n"],"mappings":";;;;;;;;;;;AAaA,MAAa,qBAAqB,WAAsD,EACtF,iBAAiB,UAAU,KAAA,UAAkB,QAAQ,SAAS,MAAM,SAAS,KAAK,IAAI,EACxF"}
package/dist/html.cjs ADDED
@@ -0,0 +1,458 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_image_url = require("./image-url-YcTed8tg.cjs");
3
+ const require_ast = require("./ast-C0BGz7X2.cjs");
4
+ let effect = require("effect");
5
+ let hast_util_to_html = require("hast-util-to-html");
6
+ //#region src/html/to-hast.ts
7
+ /**
8
+ * to-hast.ts — AST を hast (HTML の AST) にする公式コンパイラ。
9
+ *
10
+ * HTML の文字列 (`toHtml`)、JSX (cosense-x)、rehype のプラグインはすべてこの出力から作る。
11
+ * 描画の規則をここ 1 か所に置き、形式ごとに実装が分かれてずれないようにするため。
12
+ *
13
+ * ノード型ごとのハンドラの集まりで、`handlers` に渡した型だけが差し替わる。
14
+ * 既定のハンドラは `defaultHastHandlers` として公開し、オプションは `ctx.options` から読む。
15
+ * 利用者が既定の出力を包むとき、オプションを渡し直さなくて済むようにするため。
16
+ */
17
+ /** `href` に入れると script が動くスキーム。`data:text/html` があるので data: も拒む。 */
18
+ const UNSAFE_HREF_RE = /^(?:javascript|vbscript|data):/;
19
+ /** `src` に入れると script が動くスキーム。`data:` 画像は正当な使い道があるので許す。 */
20
+ const UNSAFE_SRC_RE = /^(?:javascript|vbscript):/;
21
+ /**
22
+ * スキームだけを見るために空白と制御文字を落とす。
23
+ * ブラウザは途中にタブや改行が挟まった `javascript:` もスキームとして解釈するため。
24
+ */
25
+ const schemeOf = (url) => url.replace(/[\s\p{Cc}]/gu, "").toLowerCase();
26
+ const safeUrl = (url, unsafe) => unsafe.test(schemeOf(url)) ? null : url;
27
+ /** `href` に入れて安全な URL だけを返す。script が動くスキームなら null。 */
28
+ const safeHref = (url) => safeUrl(url, UNSAFE_HREF_RE);
29
+ /** `src` に入れて安全な URL だけを返す。script が動くスキームなら null。 */
30
+ const safeSrc = (url) => safeUrl(url, UNSAFE_SRC_RE);
31
+ /** 空文字は「指定なし」とみなす。class 名や URL を空にして属性ごと消せるようにするため。 */
32
+ const nonEmpty = (value) => (0, effect.pipe)(effect.Option.fromNullable(value), effect.Option.filter((text) => text !== ""));
33
+ /** 既定の class 名。接頭辞を持たないため、利用側の CSS と名前がぶつかりうる。 */
34
+ const defaultClassNames = {
35
+ page: "page",
36
+ title: "title",
37
+ line: "line",
38
+ quote: "quote",
39
+ monospace: "monospace",
40
+ codeBlock: "code-block",
41
+ codeStart: "code-start",
42
+ codeFilename: "code-block-start",
43
+ codeBody: "code-body",
44
+ codeHighlight: "highlight",
45
+ table: "table",
46
+ indentMark: "indent-mark",
47
+ pad: "pad",
48
+ dot: "dot",
49
+ internalLink: "link",
50
+ externalLink: "link link-external",
51
+ projectLink: "link link-project",
52
+ hashtag: "hashtag",
53
+ inlineCode: "code",
54
+ image: "image",
55
+ icon: "icon",
56
+ formula: "formula",
57
+ decoration: "decoration"
58
+ };
59
+ /**
60
+ * コードブロックのファイル名から言語名を推測する。拡張子があればそれ、無ければファイル名全体。
61
+ * Cosense では `code:python` のように言語名だけを書くこともできるため。
62
+ * `highlight` に渡る言語名はこれで決めている。
63
+ */
64
+ const codeLanguageOf = (filename) => {
65
+ const dot = filename.lastIndexOf(".");
66
+ return (dot > 0 ? filename.slice(dot + 1) : filename).toLowerCase();
67
+ };
68
+ /**
69
+ * `pageUrl` の既定の実装。`/proj/page` のように区切りを含むタイトルは、
70
+ * 区切りを残したまま各段を encode する。
71
+ */
72
+ const defaultPageUrl = (title) => title.startsWith("/") ? title.split("/").map(encodeURIComponent).join("/") : `/${encodeURIComponent(title)}`;
73
+ /** 記法に書かれたページタイトル。ノード型ごとに置き場所が違うのをここで吸収する。 */
74
+ const pageTitleOf = (node) => effect.Match.value(node).pipe(effect.Match.when({ type: "hashtag" }, (tag) => tag.value), effect.Match.when({ type: "icon" }, (icon) => icon.user), effect.Match.orElse((link) => link.target));
75
+ const text = (value) => ({
76
+ type: "text",
77
+ value
78
+ });
79
+ const classList = (name) => name === void 0 ? [] : name.split(/\s+/).filter((part) => part !== "");
80
+ const element = (tagName, properties, children = []) => ({
81
+ type: "element",
82
+ tagName,
83
+ properties,
84
+ children
85
+ });
86
+ /** 値が undefined のプロパティは出さない (`exactOptionalPropertyTypes` と同じ考え)。 */
87
+ const compact = (properties) => Object.fromEntries(Object.entries(properties).filter(([, value]) => value !== void 0));
88
+ /** 空の class は属性ごと出さない。class 名を空文字にして消せるようにするため。 */
89
+ const withClass = (className, properties = {}) => {
90
+ const names = classList(className);
91
+ return names.length === 0 ? compact(properties) : {
92
+ className: names,
93
+ ...compact(properties)
94
+ };
95
+ };
96
+ /** 0 は既定値なので属性にしない。 */
97
+ const positive = (value) => value > 0 ? value : void 0;
98
+ /** 複数の class 名の設定を 1 つにつなぐ。未設定のものは飛ばす。 */
99
+ const joinClasses = (...names) => names.filter((name) => name !== void 0).join(" ");
100
+ /** ページを指すノードの遷移先。安全でなければ null (href を出さない)。 */
101
+ const pageHrefOf = (node, options) => effect.Option.getOrUndefined(nonEmpty(safeHref(options.pageUrl(pageTitleOf(node), node))));
102
+ const anchor = (className, href, label) => element("a", withClass(className, { href }), [text(label)]);
103
+ /**
104
+ * 装飾を表す要素を、内側から外側の順に並べたもの。
105
+ *
106
+ * Cosense では 1 つの記法が複数の装飾を同時に持つ (`[-/ x]` は打消しかつ斜体) ので、
107
+ * フラグの集合を入れ子の要素に開いて表現する。
108
+ */
109
+ const DECORATION_TAGS = [
110
+ [(node) => node.strike, "s"],
111
+ [(node) => node.underline, "u"],
112
+ [(node) => node.italic, "em"],
113
+ [(node) => node.bold, "strong"]
114
+ ];
115
+ /** 余白の数がインデントの深さを表し、中点はその右端に付く (Cosense Web と同じ形)。 */
116
+ const indentMark = (indent, cls) => element("span", withClass(cls.indentMark), [...Array.from({ length: indent }, () => element("span", withClass(cls.pad), [text(" ")])), element("span", withClass(cls.dot))]);
117
+ /**
118
+ * raw ノードを hast の要素の中身として扱う。型の変換はここ 1 か所に閉じる。
119
+ *
120
+ * hast の型は raw を知らない。raw の型拡張は mdast-util-to-hast が持っているが、
121
+ * それに頼ると利用者の環境で型が効くかどうかが依存の入り方で変わるので、`RawNode` を自前で持っている。
122
+ * 実行時には、文字列にするとき (hast-util-to-html の allowDangerousHtml) にそのまま埋め込まれる。
123
+ */
124
+ const asElementContents = (nodes) => nodes;
125
+ /** 要素の中身に入るノードだけにする。Root の子には doctype も来うるため。 */
126
+ const contentsOf = (result) => Array.isArray(result) ? asElementContents(result) : result.children.filter((child) => child.type !== "doctype");
127
+ const isBlank = (node) => node.type === "text" && node.value.trim() === "";
128
+ /** 空白だけのテキストを除いた、ただ 1 つの子。 */
129
+ const onlyChildOf = (children) => (0, effect.pipe)(effect.Option.some(children.filter((child) => !isBlank(child))), effect.Option.filter((meaningful) => meaningful.length === 1), effect.Option.flatMapNullable((meaningful) => meaningful[0]));
130
+ const elementNamed = (tagName) => (node) => effect.Option.liftPredicate(node, (content) => content.type === "element" && content.tagName === tagName);
131
+ /** hast の決まりでは className は配列だが、shiki は class を文字列で付ける。どちらも読む。 */
132
+ const classesOf = (value) => effect.Match.value(value).pipe(effect.Match.when(Array.isArray, (names) => names.map(String)), effect.Match.when(effect.Match.string, classList), effect.Match.orElse(() => []));
133
+ /**
134
+ * ハイライタの出力をコードブロックの code の中身にする。
135
+ * `pre > code` (shiki や lowlight の形) なら pre を剥がし、pre に付いたテーマの class と style を引き継ぐ。
136
+ */
137
+ const highlightedBody = (result) => {
138
+ const children = contentsOf(result);
139
+ return (0, effect.pipe)(onlyChildOf(children), effect.Option.flatMap(elementNamed("pre")), effect.Option.flatMap((pre) => (0, effect.pipe)(onlyChildOf(pre.children), effect.Option.flatMap(elementNamed("code")), effect.Option.map((code) => ({
140
+ children: code.children,
141
+ className: classesOf(pre.properties.className ?? pre.properties.class),
142
+ style: typeof pre.properties.style === "string" ? pre.properties.style : void 0
143
+ })))), effect.Option.getOrElse(() => ({
144
+ children,
145
+ className: [],
146
+ style: void 0
147
+ })));
148
+ };
149
+ /**
150
+ * ハイライタの出力が行ごとの要素 (shiki の `span.line`) に分かれていれば、それを行の数だけ返す。
151
+ * 行の区切りの改行 (空白だけのテキスト) は、行を別の要素にするので要らない。
152
+ */
153
+ const linesOf = (children, count) => {
154
+ const isLine = (child) => child.type === "element" && classesOf(child.properties.className ?? child.properties.class).includes("line");
155
+ return effect.Option.liftPredicate(children.filter((child) => !isBlank(child)), (lines) => lines.length === count && lines.every(isLine));
156
+ };
157
+ /** style.css がコードブロックの背景と文字の色に使う変数。 */
158
+ const THEME_VARIABLES = {
159
+ "background-color": "--cosense-code-bg",
160
+ color: "--cosense-code-text"
161
+ };
162
+ /**
163
+ * テーマの背景色と文字色 (shiki が pre に付ける style) を、style.css の変数に読み替える。
164
+ * そのまま style に置くと、利用者の CSS から上書きするのに !important が要るため。
165
+ * 変数なら、テーマの色は既定として出しつつ、普通の CSS で塗り替えられる。
166
+ */
167
+ const themeStyleOf = (style) => (0, effect.pipe)(effect.Option.fromNullable(style), effect.Option.map((declarations) => declarations.split(";").flatMap((declaration) => effect.Option.toArray(themeDeclarationOf(declaration))).join(";")), effect.Option.getOrUndefined);
168
+ /** `name: value` の 1 つ。`:` の無い壊れた宣言は落とす。 */
169
+ const themeDeclarationOf = (declaration) => (0, effect.pipe)(effect.Option.some(declaration.indexOf(":")), effect.Option.filter((colon) => colon > 0), effect.Option.map((colon) => {
170
+ const name = declaration.slice(0, colon).trim();
171
+ return `${effect.Option.getOrElse(effect.Option.fromNullable(THEME_VARIABLES[name]), () => name)}:${declaration.slice(colon + 1).trim()}`;
172
+ }));
173
+ /**
174
+ * 1 行 = 1 要素に切る (Cosense Web と同じ)。行ごとにインデントを付けられるようにするため。
175
+ * `highlight` があるときだけ、複数行にまたがる要素を壊さないよう本体をまとめる。
176
+ */
177
+ const codeBlock = (node, ctx) => {
178
+ const cls = ctx.options.classNames;
179
+ const classes = joinClasses(cls.line, cls.codeBlock);
180
+ const blockLine = (indent, child) => element("div", withClass(classes, { dataIndent: positive(indent) }), [child]);
181
+ const filename = element("span", withClass(cls.codeFilename), [text(node.filename)]);
182
+ const header = blockLine(node.indent, element("code", withClass(cls.codeStart), [filename]));
183
+ const bodyLine = (className, properties, children) => blockLine(node.indent + 1, element("code", withClass(className, properties), children));
184
+ const highlighted = (0, effect.pipe)(effect.Option.fromNullable(ctx.options.highlight), effect.Option.flatMap((highlight) => effect.Option.liftThrowable(highlight)(node.lines.map((codeLine) => codeLine.value).join("\n"), codeLanguageOf(node.filename))), effect.Option.flatMapNullable((result) => result), effect.Option.map(highlightedBody));
185
+ return effect.Option.match(highlighted, {
186
+ onNone: () => [header, ...node.lines.map((codeLine) => bodyLine(cls.codeBody, {}, ctx.node(codeLine)))],
187
+ onSome: ({ children, className, style }) => {
188
+ const names = joinClasses(cls.codeBody, cls.codeHighlight, ...className);
189
+ const properties = { style: themeStyleOf(style) };
190
+ return effect.Option.match(linesOf(children, node.lines.length), {
191
+ onSome: (lines) => [header, ...lines.map((line) => bodyLine(names, properties, [line]))],
192
+ onNone: () => [header, bodyLine(names, properties, children)]
193
+ });
194
+ }
195
+ });
196
+ };
197
+ /**
198
+ * 既定のハンドラ一式。`toHast` はこれに `handlers` を重ねてから走らせる。
199
+ *
200
+ * cosense-x のように描画を組み立て直すライブラリが、既定の部品 (行の包み方など) を使い回すためのもの。
201
+ * 既定の出力に手を加えるだけなら、これを呼ばずに `extensions` を使う。
202
+ * オプションは `ctx.options` から読むので、呼ぶ側が渡し直さなくてよい。
203
+ */
204
+ const defaultHastHandlers = {
205
+ page: (node, ctx) => [element("div", withClass(ctx.options.classNames.page), ctx.children(node))],
206
+ title: (node, ctx) => [element("h1", withClass(ctx.options.classNames.title), ctx.children(node))],
207
+ line: (node, ctx) => {
208
+ const cls = ctx.options.classNames;
209
+ const body = ctx.children(node);
210
+ const styled = node.monospace ? [element("code", withClass(cls.monospace), body)] : body;
211
+ const quoted = node.quote ? [element("blockquote", withClass(cls.quote), styled)] : styled;
212
+ const inner = quoted.length === 0 ? [element("br", {})] : quoted;
213
+ const mark = ctx.options.showPads && node.indent > 0 ? [indentMark(node.indent, cls)] : [];
214
+ return [element("div", withClass(cls.line, { dataIndent: positive(node.indent) }), [...mark, ...inner])];
215
+ },
216
+ codeBlock,
217
+ codeLine: (node) => [text(node.value)],
218
+ table: (node, ctx) => {
219
+ const caption = node.name === "" ? [] : [element("caption", {}, [text(node.name)])];
220
+ return [element("table", withClass(ctx.options.classNames.table), [...caption, element("tbody", {}, ctx.children(node))])];
221
+ },
222
+ tableRow: (node, ctx) => [element("tr", {}, ctx.children(node))],
223
+ tableCell: (node, ctx) => [element("td", {}, ctx.children(node))],
224
+ text: (node) => [text(node.value)],
225
+ internalLink: (node, ctx) => [anchor(ctx.options.classNames.internalLink, pageHrefOf(node, ctx.options), node.label)],
226
+ externalLink: (node, ctx) => [anchor(ctx.options.classNames.externalLink, effect.Option.getOrUndefined(nonEmpty(safeHref(node.target))), node.label)],
227
+ projectLink: (node, ctx) => [anchor(ctx.options.classNames.projectLink, pageHrefOf(node, ctx.options), node.label)],
228
+ hashtag: (node, ctx) => [anchor(ctx.options.classNames.hashtag, pageHrefOf(node, ctx.options), `#${node.value}`)],
229
+ inlineCode: (node, ctx) => [element("code", withClass(ctx.options.classNames.inlineCode), [text(node.value)])],
230
+ image: (node, ctx) => {
231
+ const src = effect.Option.getOrUndefined(nonEmpty(safeSrc(require_image_url.asImageSrc(node.src) ?? node.src)));
232
+ const img = element("img", withClass(ctx.options.classNames.image, {
233
+ src,
234
+ alt: "",
235
+ dataLarge: node.large ? "true" : void 0
236
+ }));
237
+ const href = (0, effect.pipe)(effect.Option.fromNullable(node.link), effect.Option.flatMap((link) => nonEmpty(safeHref(link))));
238
+ return [effect.Option.match(href, {
239
+ onNone: () => img,
240
+ onSome: (url) => element("a", { href: url }, [img])
241
+ })];
242
+ },
243
+ icon: (node, ctx) => {
244
+ const cls = ctx.options.classNames;
245
+ const src = (0, effect.pipe)(effect.Option.fromNullable(ctx.options.iconImageUrl(node)), effect.Option.flatMap((url) => nonEmpty(safeSrc(url))));
246
+ const href = pageHrefOf(node, ctx.options);
247
+ return Array.from({ length: node.count }, () => {
248
+ const body = effect.Option.match(src, {
249
+ onNone: () => text(node.user),
250
+ onSome: (url) => element("img", withClass(cls.icon, {
251
+ src: url,
252
+ alt: node.user,
253
+ title: node.user
254
+ }))
255
+ });
256
+ return element("a", withClass(joinClasses(cls.internalLink, cls.icon), { href }), [body]);
257
+ });
258
+ },
259
+ formula: (node, ctx) => [element("span", withClass(ctx.options.classNames.formula), [text(node.value)])],
260
+ decoration: (node, ctx) => {
261
+ const inner = DECORATION_TAGS.filter(([isOn]) => isOn(node)).reduce((wrapped, [, tag]) => [element(tag, {}, wrapped)], ctx.children(node));
262
+ const names = joinClasses(ctx.options.classNames.decoration, ...node.markers.map((marker) => `deco-${marker}`));
263
+ return [element("span", withClass(names, { dataSizeLevel: positive(node.sizeLevel) }), inner)];
264
+ }
265
+ };
266
+ /** オプションの既定値を埋める。 */
267
+ const resolveOptions = (options) => ({
268
+ pageUrl: options.pageUrl ?? defaultPageUrl,
269
+ iconImageUrl: options.iconImageUrl ?? (() => null),
270
+ highlight: options.highlight ?? null,
271
+ classNames: {
272
+ ...defaultClassNames,
273
+ ...options.classNames
274
+ },
275
+ showPads: options.showPads === true
276
+ });
277
+ /** ハンドラや拡張の戻り値 (1 つか配列) を、要素の中身の配列にする。 */
278
+ const contentsOfResult = (result) => asElementContents(Array.isArray(result) ? result : [result]);
279
+ /**
280
+ * ノード型で表 (ハンドラや拡張) を引く。
281
+ * 表の関数の型はキーごとに違うが、ノードの `type` でキーを引いている以上一致するので、型はここ 1 か所で合わせる。
282
+ */
283
+ const entryOf = (table, type) => effect.Option.fromNullable(table[type]);
284
+ /**
285
+ * ページ (または任意のノード) を hast にする。
286
+ *
287
+ * 1 つのノードは「既定のハンドラ (`handlers` があれば置き換え)」で作り、`extensions` を並べた順に通す。
288
+ * テキストは hast のテキストノードに入れるだけなので、エスケープは文字列にする側 (`toHtml`) が行う。
289
+ * `javascript:` のようなスキームの URL は属性ごと落とす。
290
+ * ハンドラの無いノード型 (拡張が足した独自ノード) は、中身を落とさずに子だけを出す。
291
+ */
292
+ const toHast = (node, options = {}) => {
293
+ const handlers = {
294
+ ...defaultHastHandlers,
295
+ ...options.handlers
296
+ };
297
+ const extensions = options.extensions ?? [];
298
+ const resolved = resolveOptions(options);
299
+ const render = (target, ctx) => (0, effect.pipe)(entryOf(handlers, target.type), effect.Option.match({
300
+ onNone: () => ctx.children(target),
301
+ onSome: (handler) => contentsOfResult(handler(target, ctx))
302
+ }));
303
+ const extend = (target, output, ctx) => extensions.reduce((current, extension) => (0, effect.pipe)(entryOf(extension, target.type), effect.Option.match({
304
+ onNone: () => current,
305
+ onSome: (transform) => contentsOfResult(transform(current, target, ctx))
306
+ })), output);
307
+ /**
308
+ * `target` を描くときの文脈。`ctx.node` / `ctx.children` で描くノードは、
309
+ * 渡したノードに依らず `target` の下にあるものとして描く。
310
+ * ハンドラが中身を差し替えた写し (`{ ...node, children }`) を渡しても、祖先が重ならないようにするため。
311
+ */
312
+ const contextOf = (target, ancestors) => {
313
+ const inside = [...ancestors, target];
314
+ return {
315
+ ancestors,
316
+ node: (child) => compile(child, inside),
317
+ children: (parent) => require_ast.childrenOf(parent).flatMap((child) => compile(child, inside)),
318
+ options: resolved
319
+ };
320
+ };
321
+ const compile = (target, ancestors) => {
322
+ const ctx = contextOf(target, ancestors);
323
+ return extend(target, render(target, ctx), ctx);
324
+ };
325
+ return {
326
+ type: "root",
327
+ children: compile(node, [])
328
+ };
329
+ };
330
+ //#endregion
331
+ //#region src/html/to-html.ts
332
+ const HTML_ESCAPES = {
333
+ "&": "&",
334
+ "<": "&lt;",
335
+ ">": "&gt;",
336
+ "\"": "&quot;",
337
+ "'": "&#39;"
338
+ };
339
+ /**
340
+ * `& < > " '` を実体参照に置き換える。テキストと属性値のどちらにも使える。
341
+ * `highlight` に HTML の文字列を返すハイライタを渡すとき、色付けしない部分のエスケープに使う。
342
+ */
343
+ const escapeHtml = (value) => value.replace(/[&<>"']/g, (char) => HTML_ESCAPES[char] ?? char);
344
+ /** 文字列を返すハイライタを、hast の raw ノードを返す形にする。 */
345
+ const asHastHighlighter = (highlight) => (code, language) => {
346
+ const result = highlight(code, language);
347
+ return typeof result === "string" ? [{
348
+ type: "raw",
349
+ value: result
350
+ }] : result;
351
+ };
352
+ /**
353
+ * ページ (または任意のノード) を HTML 文字列にする。`hast-util-to-html(toHast(node, options))` と同じ。
354
+ *
355
+ * テキストと属性値はエスケープし、`javascript:` のようなスキームの URL は属性ごと落とす。
356
+ * `highlight` が返した文字列と、`handlers` が返した raw ノードはそのまま埋め込むので、
357
+ * そこでのエスケープは書いた人の責任になる。
358
+ */
359
+ const toHtml = (node, options = {}) => {
360
+ const { highlight, style, ...rest } = options;
361
+ const hast = toHast(node, {
362
+ ...rest,
363
+ ...highlight === void 0 ? {} : { highlight: asHastHighlighter(highlight) }
364
+ });
365
+ const html = (0, hast_util_to_html.toHtml)(hast, {
366
+ allowDangerousHtml: true,
367
+ characterReferences: { useNamedReferences: true }
368
+ });
369
+ return style === void 0 ? html : `<style>${style}</style>${html}`;
370
+ };
371
+ //#endregion
372
+ //#region src/html/code-line-numbers.ts
373
+ /**
374
+ * code-line-numbers.ts — コードブロックに行番号を付ける描画の拡張。
375
+ */
376
+ /** 行の要素に行番号と桁数を付ける。要素でないもの (テキストなど) には付ける場所が無いのでそのまま。 */
377
+ const withLineNumber = (digits) => (line, number) => effect.Match.value(line).pipe(effect.Match.when({ type: "element" }, (element) => ({
378
+ ...element,
379
+ properties: {
380
+ ...element.properties,
381
+ dataLine: number,
382
+ dataLineDigits: digits
383
+ }
384
+ })), effect.Match.orElse(() => line));
385
+ /**
386
+ * コードブロックの出力 (先頭がヘッダ行、続いて本体行) に行番号を付ける。
387
+ * 本体行が行の数だけ並んでいるときだけ付ける。ひと塊にまとめた出力や、
388
+ * `handlers` が別の形に置き換えた出力では、行と番号が対応しないため。
389
+ */
390
+ const numberLines = (output, count) => (0, effect.pipe)(effect.Option.some(output), effect.Option.filter((lines) => lines.length === count + 1), effect.Option.map(([header, ...body]) => {
391
+ const number = withLineNumber(String(count).length);
392
+ return [...effect.Option.toArray(effect.Option.fromNullable(header)), ...body.map((line, index) => number(line, index + 1))];
393
+ }), effect.Option.getOrElse(() => output));
394
+ /**
395
+ * コードブロックの本体行に、1 から数えた行番号 (`data-line`) と桁数 (`data-line-digits`) を付ける拡張。
396
+ *
397
+ * ```ts
398
+ * toHtml(page, { extensions: [codeLineNumbers()] })
399
+ * ```
400
+ *
401
+ * 番号を見せるのは CSS の役目 (`@cosense-toolbox/style` は `data-line` を見て行の左に番号を出す)。
402
+ * 色付けしてひと塊にまとめたブロックは、行と番号が対応しないので付けない。
403
+ */
404
+ const codeLineNumbers = () => ({ codeBlock: (output, node) => numberLines(output, node.lines.length) });
405
+ //#endregion
406
+ //#region src/html/table-cell-line-breaks.ts
407
+ /**
408
+ * table-cell-line-breaks.ts — テーブルのセルの中の文字列を改行にする描画の拡張。
409
+ *
410
+ * Cosense のセルには改行を書けないので、`\n` のような文字の並びを代わりに書いておき、
411
+ * 描画のときに `<br>` にする。記法ではなく見た目の約束なので、パーサーではなく描画の拡張にしている。
412
+ */
413
+ const lineBreak = () => ({
414
+ type: "element",
415
+ tagName: "br",
416
+ properties: {},
417
+ children: []
418
+ });
419
+ /** 空でない文字列だけを text にする。区切った部分が空なら何も出さない。 */
420
+ const textOf = (value) => (0, effect.pipe)(effect.Option.some(value), effect.Option.filter((part) => part !== ""), effect.Option.map((part) => ({
421
+ type: "text",
422
+ value: part
423
+ })));
424
+ /** 文字列を `marker` で区切り、間に `<br>` を挟む。 */
425
+ const breakText = (value, marker) => value.split(marker).flatMap((part, index) => [...index === 0 ? [] : [lineBreak()], ...effect.Option.toArray(textOf(part))]);
426
+ /** 出力のうち text だけを区切る。`handlers.text` が要素を返したときは、そのまま残す。 */
427
+ const breakContent = (marker) => (content) => effect.Match.value(content).pipe(effect.Match.when({ type: "text" }, (text) => breakText(text.value, marker)), effect.Match.orElse((other) => [other]));
428
+ const isTableCell = (node) => node.type === "tableCell";
429
+ /**
430
+ * テーブルのセルの中の `marker` を `<br>` にする描画の拡張。
431
+ *
432
+ * 当てるのは、セルの中にある AST の text ノード (記法の外の地の文) だけ。
433
+ * コード・数式・リンクの表示は text ノードではないので、`classNames` や `handlers` で
434
+ * 出力を変えても、その中には当たらない。装飾の中身は text ノードなので当たる。
435
+ * `marker` は文字列そのままで探し (正規表現としては読まない)、区切った文字は通常どおりエスケープされる。
436
+ * `marker` が空文字なら何もしない。
437
+ *
438
+ * @example
439
+ * toHtml(page, { extensions: [tableCellLineBreaks('\\n')] })
440
+ */
441
+ const tableCellLineBreaks = (marker) => ({ text: (output, _node, ctx) => (0, effect.pipe)(effect.Option.some(marker), effect.Option.filter((value) => value !== ""), effect.Option.filter(() => ctx.ancestors.some(isTableCell)), effect.Option.match({
442
+ onNone: () => output,
443
+ onSome: (value) => output.flatMap(breakContent(value))
444
+ })) });
445
+ //#endregion
446
+ exports.codeLanguageOf = codeLanguageOf;
447
+ exports.codeLineNumbers = codeLineNumbers;
448
+ exports.defaultClassNames = defaultClassNames;
449
+ exports.defaultHastHandlers = defaultHastHandlers;
450
+ exports.defaultPageUrl = defaultPageUrl;
451
+ exports.escapeHtml = escapeHtml;
452
+ exports.safeHref = safeHref;
453
+ exports.safeSrc = safeSrc;
454
+ exports.tableCellLineBreaks = tableCellLineBreaks;
455
+ exports.toHast = toHast;
456
+ exports.toHtml = toHtml;
457
+
458
+ //# sourceMappingURL=html.cjs.map