@diplodoc/folding-headings-extension 0.1.3 → 0.2.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/build/plugin/index.js
CHANGED
|
@@ -105,10 +105,10 @@ var headingBlockRule = (state, startLine, _endLine, silent) => {
|
|
|
105
105
|
return true;
|
|
106
106
|
};
|
|
107
107
|
|
|
108
|
+
// src/plugin/sectionsCoreRule.ts
|
|
109
|
+
var import_utils = require("@diplodoc/utils");
|
|
110
|
+
|
|
108
111
|
// src/plugin/utils.ts
|
|
109
|
-
function generateID() {
|
|
110
|
-
return DATA_KEY + "-" + Math.random().toString(36).substr(2, 8);
|
|
111
|
-
}
|
|
112
112
|
function headingLevel(header) {
|
|
113
113
|
return parseInt(header.charAt(1), 10);
|
|
114
114
|
}
|
|
@@ -150,102 +150,110 @@ function dynrequire(module) {
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
// src/plugin/sectionsCoreRule.ts
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
153
|
+
function createSectionsCoreRule(externalGenerateID) {
|
|
154
|
+
const generateID = externalGenerateID ?? (0, import_utils.createIDGeneratorByStrategy)("random");
|
|
155
|
+
return (state) => {
|
|
156
|
+
const Token = state.Token;
|
|
157
|
+
const tokens = [];
|
|
158
|
+
const sections = [];
|
|
159
|
+
let nestedLevel = 0;
|
|
160
|
+
for (const token of state.tokens) {
|
|
161
|
+
if (token.type.search(TokenType.Heading) !== 0) {
|
|
162
|
+
nestedLevel += token.nesting;
|
|
163
|
+
}
|
|
164
|
+
if (last(sections) && nestedLevel < last(sections).nesting) {
|
|
165
|
+
closeSectionsToCurrentNesting(nestedLevel);
|
|
166
|
+
}
|
|
167
|
+
const hasFolding = token.markup.endsWith("#+");
|
|
168
|
+
if (token.type === TokenType.HeadingOpen) {
|
|
169
|
+
const section = {
|
|
170
|
+
header: headingLevel(token.tag),
|
|
171
|
+
nesting: nestedLevel
|
|
172
|
+
};
|
|
173
|
+
closeSections(section);
|
|
174
|
+
if (hasFolding) {
|
|
175
|
+
tokens.push(openSection());
|
|
176
|
+
sections.push(section);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
tokens.push(token);
|
|
180
|
+
if (token.type === TokenType.HeadingClose && hasFolding) {
|
|
181
|
+
tokens.push(openContent());
|
|
182
|
+
}
|
|
161
183
|
}
|
|
162
|
-
|
|
163
|
-
|
|
184
|
+
closeAllSections();
|
|
185
|
+
if (state.tokens.length !== tokens.length) {
|
|
186
|
+
state.env ??= {};
|
|
187
|
+
state.env[ENV_FLAG_NAME] = true;
|
|
164
188
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
tokens.push(openSection());
|
|
174
|
-
sections.push(section);
|
|
175
|
-
}
|
|
189
|
+
state.tokens = tokens;
|
|
190
|
+
function openSection() {
|
|
191
|
+
const t = new Token(TokenType.SectionOpen, "section", 1);
|
|
192
|
+
t.attrPush(["class", SectionCN.Section]);
|
|
193
|
+
t.attrPush([SectionAttr.DataKey, DATA_KEY]);
|
|
194
|
+
t.attrPush([SectionAttr.DataId, generateID(DATA_KEY)]);
|
|
195
|
+
t.block = true;
|
|
196
|
+
return t;
|
|
176
197
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
198
|
+
function closeSection() {
|
|
199
|
+
const t = new Token(TokenType.SectionClose, "section", -1);
|
|
200
|
+
t.block = true;
|
|
201
|
+
return t;
|
|
180
202
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
state.tokens = tokens;
|
|
188
|
-
function openSection() {
|
|
189
|
-
const t = new Token(TokenType.SectionOpen, "section", 1);
|
|
190
|
-
t.attrPush(["class", SectionCN.Section]);
|
|
191
|
-
t.attrPush([SectionAttr.DataKey, DATA_KEY]);
|
|
192
|
-
t.attrPush([SectionAttr.DataId, generateID()]);
|
|
193
|
-
t.block = true;
|
|
194
|
-
return t;
|
|
195
|
-
}
|
|
196
|
-
function closeSection() {
|
|
197
|
-
const t = new Token(TokenType.SectionClose, "section", -1);
|
|
198
|
-
t.block = true;
|
|
199
|
-
return t;
|
|
200
|
-
}
|
|
201
|
-
function openContent() {
|
|
202
|
-
const t = new Token(TokenType.ContentOpen, "div", 1);
|
|
203
|
-
t.attrPush(["class", SectionCN.Content]);
|
|
204
|
-
t.block = true;
|
|
205
|
-
return t;
|
|
206
|
-
}
|
|
207
|
-
function closeContent() {
|
|
208
|
-
const t = new Token(TokenType.ContentClose, "div", -1);
|
|
209
|
-
t.block = true;
|
|
210
|
-
return t;
|
|
211
|
-
}
|
|
212
|
-
function closeSections(section) {
|
|
213
|
-
while (last(sections) && // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
214
|
-
section.header <= last(sections).header && // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
215
|
-
section.nesting <= last(sections).nesting) {
|
|
216
|
-
sections.pop();
|
|
217
|
-
tokens.push(closeContent());
|
|
218
|
-
tokens.push(closeSection());
|
|
203
|
+
function openContent() {
|
|
204
|
+
const t = new Token(TokenType.ContentOpen, "div", 1);
|
|
205
|
+
t.attrPush(["class", SectionCN.Content]);
|
|
206
|
+
t.block = true;
|
|
207
|
+
return t;
|
|
219
208
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
tokens.push(closeContent());
|
|
225
|
-
tokens.push(closeSection());
|
|
209
|
+
function closeContent() {
|
|
210
|
+
const t = new Token(TokenType.ContentClose, "div", -1);
|
|
211
|
+
t.block = true;
|
|
212
|
+
return t;
|
|
226
213
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
214
|
+
function closeSections(section) {
|
|
215
|
+
while (last(sections) && // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
216
|
+
section.header <= last(sections).header && // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
217
|
+
section.nesting <= last(sections).nesting) {
|
|
218
|
+
sections.pop();
|
|
219
|
+
tokens.push(closeContent());
|
|
220
|
+
tokens.push(closeSection());
|
|
221
|
+
}
|
|
232
222
|
}
|
|
233
|
-
|
|
234
|
-
|
|
223
|
+
function closeSectionsToCurrentNesting(nesting) {
|
|
224
|
+
while (last(sections) && nesting < last(sections).nesting) {
|
|
225
|
+
sections.pop();
|
|
226
|
+
tokens.push(closeContent());
|
|
227
|
+
tokens.push(closeSection());
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function closeAllSections() {
|
|
231
|
+
while (sections.pop()) {
|
|
232
|
+
tokens.push(closeContent());
|
|
233
|
+
tokens.push(closeSection());
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
}
|
|
235
238
|
|
|
236
239
|
// src/plugin/plugin.ts
|
|
237
|
-
|
|
238
|
-
md
|
|
239
|
-
|
|
240
|
-
|
|
240
|
+
function createFoldingHeadingPlugin(generateID) {
|
|
241
|
+
return (md) => {
|
|
242
|
+
md.block.ruler.at("heading", headingBlockRule, {
|
|
243
|
+
alt: ["paragraph", "reference", "blockquote"]
|
|
244
|
+
});
|
|
245
|
+
md.core.ruler.push("heading_sections", createSectionsCoreRule(generateID));
|
|
246
|
+
};
|
|
247
|
+
}
|
|
241
248
|
|
|
242
249
|
// src/plugin/transform.ts
|
|
243
250
|
var registerTransform = (md, {
|
|
244
251
|
runtime,
|
|
245
252
|
bundle,
|
|
246
|
-
output
|
|
253
|
+
output,
|
|
254
|
+
generateID
|
|
247
255
|
}) => {
|
|
248
|
-
md.use(
|
|
256
|
+
md.use(createFoldingHeadingPlugin(generateID));
|
|
249
257
|
md.core.ruler.push("heading_sections_after", ({ env }) => {
|
|
250
258
|
hidden(env, "bundled", /* @__PURE__ */ new Set());
|
|
251
259
|
if (env?.[ENV_FLAG_NAME]) {
|
|
@@ -269,11 +277,12 @@ function transform(options = {}) {
|
|
|
269
277
|
script: "_assets/folding-headings-extension.js",
|
|
270
278
|
style: "_assets/folding-headings-extension.css"
|
|
271
279
|
};
|
|
272
|
-
const plugin = function(md, { output = "." } = {}) {
|
|
280
|
+
const plugin = function(md, { output = ".", generateID } = {}) {
|
|
273
281
|
registerTransform(md, {
|
|
274
282
|
runtime,
|
|
275
283
|
bundle,
|
|
276
|
-
output
|
|
284
|
+
output,
|
|
285
|
+
generateID
|
|
277
286
|
});
|
|
278
287
|
};
|
|
279
288
|
Object.assign(plugin, {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../src/plugin/index.ts", "../../src/common/const.ts", "../../src/plugin/const.ts", "../../src/plugin/headingBlockRule.ts", "../../src/plugin/
|
|
4
|
-
"sourcesContent": ["export type {TransformOptions} from './transform';\nexport {transform} from './transform';\nexport {TokenType} from './const';\n", "export const DATA_KEY = 'heading-section';\n\nexport const SectionAttr = {\n DataId: 'data-diplodoc-id',\n DataKey: 'data-diplodoc-key',\n} as const;\n\nexport const SectionCN = {\n Section: 'heading-section',\n Content: 'heading-section-content',\n};\n", "export {SectionCN, DATA_KEY, SectionAttr} from '../common/const';\n\nexport const ENV_FLAG_NAME = 'has-folding-headings';\n\nexport const TokenType = {\n Heading: 'heading',\n HeadingOpen: 'heading_open',\n HeadingClose: 'heading_close',\n Section: 'heading_section',\n SectionOpen: 'heading_section_open',\n SectionClose: 'heading_section_close',\n Content: 'heading_section_content',\n ContentOpen: 'heading_section_content_open',\n ContentClose: 'heading_section_content_close',\n} as const;\n", "import type ParserBlock from 'markdown-it/lib/parser_block';\n\nimport {TokenType} from './const';\n\n// copied from https://github.com/markdown-it/markdown-it/blob/14.1.0/lib/rules_block/heading.mjs\n// modified: support syntax ###+ for folding headings\nexport const headingBlockRule: ParserBlock.RuleBlock = (state, startLine, _endLine, silent) => {\n const {isSpace} = state.md.utils;\n\n let pos = state.bMarks[startLine] + state.tShift[startLine];\n let max = state.eMarks[startLine];\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n\n let ch = state.src.charCodeAt(pos);\n\n if (ch !== 0x23 /* # */ || pos >= max) {\n return false;\n }\n\n // count heading level\n let level = 1;\n ch = state.src.charCodeAt(++pos);\n while (ch === 0x23 /* # */ && pos < max && level <= 6) {\n level++;\n ch = state.src.charCodeAt(++pos);\n }\n\n let folding = false;\n if (ch === 0x2b /* + */) {\n folding = true;\n ch = state.src.charCodeAt(++pos);\n }\n\n if (level > 6 || (pos < max && !isSpace(ch))) {\n return false;\n }\n\n if (silent) {\n return true;\n }\n\n // Let's cut tails like ' ### ' from the end of string\n\n max = state.skipSpacesBack(max, pos);\n const tmp = state.skipCharsBack(max, 0x23, pos); // #\n if (tmp > pos && isSpace(state.src.charCodeAt(tmp - 1))) {\n max = tmp;\n }\n\n state.line = startLine + 1;\n\n let token = state.push(TokenType.HeadingOpen, 'h' + String(level), 1);\n token.markup = '########'.slice(0, level) + (folding ? '+' : '');\n token.map = [startLine, state.line];\n if (folding) {\n token.meta ||= {};\n token.meta.folding = true;\n }\n\n token = state.push('inline', '', 0);\n token.content = state.src.slice(pos, max).trim();\n token.map = [startLine, state.line];\n token.children = [];\n\n token = state.push(TokenType.HeadingClose, 'h' + String(level), -1);\n token.markup = '########'.slice(0, level) + (folding ? '+' : '');\n if (folding) {\n token.meta ||= {};\n token.meta.folding = true;\n }\n\n return true;\n};\n", "import {DATA_KEY} from './const';\n\nexport function generateID() {\n return DATA_KEY + '-' + Math.random().toString(36).substr(2, 8);\n}\n\nexport function headingLevel(header: string) {\n return parseInt(header.charAt(1), 10);\n}\n\nexport function last<T>(arr: T[]): T | undefined {\n return arr[arr.length - 1];\n}\n\nexport function hidden<B extends Record<string | symbol, unknown>, F extends string | symbol, V>(\n box: B,\n field: F,\n value: V,\n) {\n if (!(field in box)) {\n Object.defineProperty(box, field, {\n enumerable: false,\n value: value,\n });\n }\n\n return box as B & Record<F, V>;\n}\n\nexport type Runtime = {\n script: string;\n style: string;\n};\n\ndeclare const __dirname: string;\nexport function copyRuntime(\n {runtime, output}: {runtime: Runtime; output: string},\n cache: Set<string>,\n) {\n const PATH_TO_RUNTIME = '../runtime';\n const {join, resolve} = dynrequire('node:path');\n const runtimeFiles = {\n 'index.js': runtime.script,\n 'index.css': runtime.style,\n };\n for (const [originFile, outputFile] of Object.entries(runtimeFiles)) {\n const file = join(PATH_TO_RUNTIME, originFile);\n if (!cache.has(file)) {\n cache.add(file);\n copy(resolve(__dirname, file), join(output, outputFile));\n }\n }\n}\n\nexport function copy(from: string, to: string) {\n const {mkdirSync, copyFileSync} = dynrequire('node:fs');\n const {dirname} = dynrequire('node:path');\n\n mkdirSync(dirname(to), {recursive: true});\n copyFileSync(from, to);\n}\n\n/*\n * Runtime require hidden for builders.\n * Used for nodejs api\n */\nexport function dynrequire(module: string) {\n // eslint-disable-next-line no-eval\n return eval(`require('${module}')`);\n}\n", "import type Core from 'markdown-it/lib/parser_core';\n\nimport {DATA_KEY, ENV_FLAG_NAME, SectionAttr, SectionCN, TokenType} from './const';\nimport {generateID, headingLevel, last} from './utils';\n\ntype Section = {header: number; nesting: number};\n\nexport const sectionsCoreRule: Core.RuleCore = (state) => {\n const Token = state.Token;\n const tokens: typeof state.tokens = []; // output\n const sections: Section[] = [];\n let nestedLevel = 0;\n\n for (const token of state.tokens) {\n // record level of nesting\n if (token.type.search(TokenType.Heading) !== 0) {\n nestedLevel += token.nesting;\n }\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n if (last(sections) && nestedLevel < last(sections)!.nesting) {\n closeSectionsToCurrentNesting(nestedLevel);\n }\n\n const hasFolding = token.markup.endsWith('#+');\n\n // add sections before headers\n if (token.type === TokenType.HeadingOpen) {\n const section: Section = {\n header: headingLevel(token.tag),\n nesting: nestedLevel,\n };\n closeSections(section);\n if (hasFolding) {\n tokens.push(openSection());\n sections.push(section);\n }\n }\n\n tokens.push(token);\n\n if (token.type === TokenType.HeadingClose && hasFolding) {\n tokens.push(openContent());\n }\n }\n\n // end for every token\n closeAllSections();\n\n if (state.tokens.length !== tokens.length) {\n state.env ??= {};\n state.env[ENV_FLAG_NAME] = true;\n }\n\n state.tokens = tokens;\n\n function openSection() {\n const t = new Token(TokenType.SectionOpen, 'section', 1);\n t.attrPush(['class', SectionCN.Section]);\n t.attrPush([SectionAttr.DataKey, DATA_KEY]);\n t.attrPush([SectionAttr.DataId, generateID()]);\n t.block = true;\n return t;\n }\n\n function closeSection() {\n const t = new Token(TokenType.SectionClose, 'section', -1);\n t.block = true;\n return t;\n }\n\n function openContent() {\n const t = new Token(TokenType.ContentOpen, 'div', 1);\n t.attrPush(['class', SectionCN.Content]);\n t.block = true;\n return t;\n }\n\n function closeContent() {\n const t = new Token(TokenType.ContentClose, 'div', -1);\n t.block = true;\n return t;\n }\n\n function closeSections(section: Section) {\n while (\n last(sections) &&\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n section.header <= last(sections)!.header &&\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n section.nesting <= last(sections)!.nesting\n ) {\n sections.pop();\n tokens.push(closeContent());\n tokens.push(closeSection());\n }\n }\n\n function closeSectionsToCurrentNesting(nesting: number) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n while (last(sections) && nesting < last(sections)!.nesting) {\n sections.pop();\n tokens.push(closeContent());\n tokens.push(closeSection());\n }\n }\n\n function closeAllSections() {\n while (sections.pop()) {\n tokens.push(closeContent());\n tokens.push(closeSection());\n }\n }\n};\n", "import type {PluginSimple} from 'markdown-it';\n\nimport {headingBlockRule} from './headingBlockRule';\nimport {sectionsCoreRule} from './sectionsCoreRule';\n\nexport const foldingHeadingPlugin: PluginSimple = (md) => {\n md.block.ruler.at('heading', headingBlockRule, {alt: ['paragraph', 'reference', 'blockquote']});\n md.core.ruler.push('heading_sections', sectionsCoreRule);\n};\n", "import type MarkdownIt from 'markdown-it';\nimport type {PluginWithOptions} from 'markdown-it';\n\nimport {ENV_FLAG_NAME} from './const';\nimport {foldingHeadingPlugin} from './plugin';\nimport {type Runtime, copyRuntime, dynrequire, hidden} from './utils';\n\nconst registerTransform = (\n md: MarkdownIt,\n {\n runtime,\n bundle,\n output,\n }: Pick<NormalizedPluginOptions, 'bundle' | 'runtime'> & {\n output: string;\n },\n) => {\n md.use(foldingHeadingPlugin);\n md.core.ruler.push('heading_sections_after', ({env}) => {\n hidden(env, 'bundled', new Set<string>());\n\n if (env?.[ENV_FLAG_NAME]) {\n env.meta = env.meta || {};\n env.meta.script = env.meta.script || [];\n env.meta.script.push(runtime.script);\n env.meta.style = env.meta.style || [];\n env.meta.style.push(runtime.style);\n\n if (bundle) {\n copyRuntime({runtime, output}, env.bundled);\n }\n }\n });\n};\n\ntype NormalizedPluginOptions = Omit<TransformOptions, 'runtime'> & {\n runtime: Runtime;\n};\n\nexport type TransformOptions = {\n runtime?:\n | string\n | {\n script: string;\n style: string;\n };\n bundle?: boolean;\n};\n\ntype InputOptions = {\n destRoot: string;\n};\n\nexport function transform(options: Partial<TransformOptions> = {}) {\n const {bundle = true} = options;\n\n if (bundle && typeof options.runtime === 'string') {\n throw new TypeError('Option `runtime` should be record when `bundle` is enabled.');\n }\n\n const runtime: Runtime =\n typeof options.runtime === 'string'\n ? {script: options.runtime, style: options.runtime}\n : options.runtime || {\n script: '_assets/folding-headings-extension.js',\n style: '_assets/folding-headings-extension.css',\n };\n\n const plugin: PluginWithOptions<{output?: string}> = function (\n md: MarkdownIt,\n {output = '.'} = {},\n ) {\n registerTransform(md, {\n runtime,\n bundle,\n output,\n });\n };\n\n Object.assign(plugin, {\n collect(input: string, {destRoot = '.'}: InputOptions) {\n const MdIt = dynrequire('markdown-it');\n const md = new MdIt().use((md: MarkdownIt) => {\n registerTransform(md, {\n runtime,\n bundle,\n output: destRoot,\n });\n });\n\n md.parse(input, {});\n },\n });\n\n return plugin;\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,WAAW;AAEjB,IAAM,cAAc;AAAA,EACvB,QAAQ;AAAA,EACR,SAAS;AACb;AAEO,IAAM,YAAY;AAAA,EACrB,SAAS;AAAA,EACT,SAAS;AACb;;;ACRO,IAAM,gBAAgB;AAEtB,IAAM,YAAY;AAAA,EACrB,SAAS;AAAA,EACT,aAAa;AAAA,EACb,cAAc;AAAA,EACd,SAAS;AAAA,EACT,aAAa;AAAA,EACb,cAAc;AAAA,EACd,SAAS;AAAA,EACT,aAAa;AAAA,EACb,cAAc;AAClB;;;ACRO,IAAM,mBAA0C,CAAC,OAAO,WAAW,UAAU,WAAW;AAC3F,QAAM,EAAC,QAAO,IAAI,MAAM,GAAG;AAE3B,MAAI,MAAM,MAAM,OAAO,SAAS,IAAI,MAAM,OAAO,SAAS;AAC1D,MAAI,MAAM,MAAM,OAAO,SAAS;AAGhC,MAAI,MAAM,OAAO,SAAS,IAAI,MAAM,aAAa,GAAG;AAChD,WAAO;AAAA,EACX;AAEA,MAAI,KAAK,MAAM,IAAI,WAAW,GAAG;AAEjC,MAAI,OAAO,MAAgB,OAAO,KAAK;AACnC,WAAO;AAAA,EACX;AAGA,MAAI,QAAQ;AACZ,OAAK,MAAM,IAAI,WAAW,EAAE,GAAG;AAC/B,SAAO,OAAO,MAAgB,MAAM,OAAO,SAAS,GAAG;AACnD;AACA,SAAK,MAAM,IAAI,WAAW,EAAE,GAAG;AAAA,EACnC;AAEA,MAAI,UAAU;AACd,MAAI,OAAO,IAAc;AACrB,cAAU;AACV,SAAK,MAAM,IAAI,WAAW,EAAE,GAAG;AAAA,EACnC;AAEA,MAAI,QAAQ,KAAM,MAAM,OAAO,CAAC,QAAQ,EAAE,GAAI;AAC1C,WAAO;AAAA,EACX;AAEA,MAAI,QAAQ;AACR,WAAO;AAAA,EACX;AAIA,QAAM,MAAM,eAAe,KAAK,GAAG;AACnC,QAAM,MAAM,MAAM,cAAc,KAAK,IAAM,GAAG;AAC9C,MAAI,MAAM,OAAO,QAAQ,MAAM,IAAI,WAAW,MAAM,CAAC,CAAC,GAAG;AACrD,UAAM;AAAA,EACV;AAEA,QAAM,OAAO,YAAY;AAEzB,MAAI,QAAQ,MAAM,KAAK,UAAU,aAAa,MAAM,OAAO,KAAK,GAAG,CAAC;AACpE,QAAM,SAAS,WAAW,MAAM,GAAG,KAAK,KAAK,UAAU,MAAM;AAC7D,QAAM,MAAM,CAAC,WAAW,MAAM,IAAI;AAClC,MAAI,SAAS;AACT,UAAM,SAAS,CAAC;AAChB,UAAM,KAAK,UAAU;AAAA,EACzB;AAEA,UAAQ,MAAM,KAAK,UAAU,IAAI,CAAC;AAClC,QAAM,UAAU,MAAM,IAAI,MAAM,KAAK,GAAG,EAAE,KAAK;AAC/C,QAAM,MAAM,CAAC,WAAW,MAAM,IAAI;AAClC,QAAM,WAAW,CAAC;AAElB,UAAQ,MAAM,KAAK,UAAU,cAAc,MAAM,OAAO,KAAK,GAAG,EAAE;AAClE,QAAM,SAAS,WAAW,MAAM,GAAG,KAAK,KAAK,UAAU,MAAM;AAC7D,MAAI,SAAS;AACT,UAAM,SAAS,CAAC;AAChB,UAAM,KAAK,UAAU;AAAA,EACzB;AAEA,SAAO;AACX;;;
|
|
3
|
+
"sources": ["../../src/plugin/index.ts", "../../src/common/const.ts", "../../src/plugin/const.ts", "../../src/plugin/headingBlockRule.ts", "../../src/plugin/sectionsCoreRule.ts", "../../src/plugin/utils.ts", "../../src/plugin/plugin.ts", "../../src/plugin/transform.ts"],
|
|
4
|
+
"sourcesContent": ["export type {TransformOptions} from './transform';\nexport {transform} from './transform';\nexport {TokenType} from './const';\n", "export const DATA_KEY = 'heading-section';\n\nexport const SectionAttr = {\n DataId: 'data-diplodoc-id',\n DataKey: 'data-diplodoc-key',\n} as const;\n\nexport const SectionCN = {\n Section: 'heading-section',\n Content: 'heading-section-content',\n};\n", "export {SectionCN, DATA_KEY, SectionAttr} from '../common/const';\n\nexport const ENV_FLAG_NAME = 'has-folding-headings';\n\nexport const TokenType = {\n Heading: 'heading',\n HeadingOpen: 'heading_open',\n HeadingClose: 'heading_close',\n Section: 'heading_section',\n SectionOpen: 'heading_section_open',\n SectionClose: 'heading_section_close',\n Content: 'heading_section_content',\n ContentOpen: 'heading_section_content_open',\n ContentClose: 'heading_section_content_close',\n} as const;\n", "import type ParserBlock from 'markdown-it/lib/parser_block';\n\nimport {TokenType} from './const';\n\n// copied from https://github.com/markdown-it/markdown-it/blob/14.1.0/lib/rules_block/heading.mjs\n// modified: support syntax ###+ for folding headings\nexport const headingBlockRule: ParserBlock.RuleBlock = (state, startLine, _endLine, silent) => {\n const {isSpace} = state.md.utils;\n\n let pos = state.bMarks[startLine] + state.tShift[startLine];\n let max = state.eMarks[startLine];\n\n // if it's indented more than 3 spaces, it should be a code block\n if (state.sCount[startLine] - state.blkIndent >= 4) {\n return false;\n }\n\n let ch = state.src.charCodeAt(pos);\n\n if (ch !== 0x23 /* # */ || pos >= max) {\n return false;\n }\n\n // count heading level\n let level = 1;\n ch = state.src.charCodeAt(++pos);\n while (ch === 0x23 /* # */ && pos < max && level <= 6) {\n level++;\n ch = state.src.charCodeAt(++pos);\n }\n\n let folding = false;\n if (ch === 0x2b /* + */) {\n folding = true;\n ch = state.src.charCodeAt(++pos);\n }\n\n if (level > 6 || (pos < max && !isSpace(ch))) {\n return false;\n }\n\n if (silent) {\n return true;\n }\n\n // Let's cut tails like ' ### ' from the end of string\n\n max = state.skipSpacesBack(max, pos);\n const tmp = state.skipCharsBack(max, 0x23, pos); // #\n if (tmp > pos && isSpace(state.src.charCodeAt(tmp - 1))) {\n max = tmp;\n }\n\n state.line = startLine + 1;\n\n let token = state.push(TokenType.HeadingOpen, 'h' + String(level), 1);\n token.markup = '########'.slice(0, level) + (folding ? '+' : '');\n token.map = [startLine, state.line];\n if (folding) {\n token.meta ||= {};\n token.meta.folding = true;\n }\n\n token = state.push('inline', '', 0);\n token.content = state.src.slice(pos, max).trim();\n token.map = [startLine, state.line];\n token.children = [];\n\n token = state.push(TokenType.HeadingClose, 'h' + String(level), -1);\n token.markup = '########'.slice(0, level) + (folding ? '+' : '');\n if (folding) {\n token.meta ||= {};\n token.meta.folding = true;\n }\n\n return true;\n};\n", "import type Core from 'markdown-it/lib/parser_core';\nimport type {IDGenerator} from '@diplodoc/utils';\n\nimport {createIDGeneratorByStrategy} from '@diplodoc/utils';\n\nimport {DATA_KEY, ENV_FLAG_NAME, SectionAttr, SectionCN, TokenType} from './const';\nimport {headingLevel, last} from './utils';\n\ntype Section = {header: number; nesting: number};\n\n/**\n * Creates a core rule that wraps folding headings in `<section>` elements with unique IDs.\n * @param externalGenerateID - Optional external ID generator (e.g. from MarkdownItPluginOpts).\n * When provided, ensures all plugins share the same per-file generator.\n * When omitted, uses random fallback behavior.\n * @returns Markdown-it core rule that injects section wrapper tokens around folding headings.\n */\nexport function createSectionsCoreRule(externalGenerateID?: IDGenerator): Core.RuleCore {\n // Use the external generator if provided, otherwise use random fallback.\n // Random IDs are the default behavior for production builds.\n const generateID: IDGenerator =\n externalGenerateID ?? (createIDGeneratorByStrategy('random') as IDGenerator);\n\n return (state) => {\n const Token = state.Token;\n const tokens: typeof state.tokens = []; // output\n const sections: Section[] = [];\n let nestedLevel = 0;\n\n for (const token of state.tokens) {\n // record level of nesting\n if (token.type.search(TokenType.Heading) !== 0) {\n nestedLevel += token.nesting;\n }\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n if (last(sections) && nestedLevel < last(sections)!.nesting) {\n closeSectionsToCurrentNesting(nestedLevel);\n }\n\n const hasFolding = token.markup.endsWith('#+');\n\n // add sections before headers\n if (token.type === TokenType.HeadingOpen) {\n const section: Section = {\n header: headingLevel(token.tag),\n nesting: nestedLevel,\n };\n closeSections(section);\n if (hasFolding) {\n tokens.push(openSection());\n sections.push(section);\n }\n }\n\n tokens.push(token);\n\n if (token.type === TokenType.HeadingClose && hasFolding) {\n tokens.push(openContent());\n }\n }\n\n // end for every token\n closeAllSections();\n\n if (state.tokens.length !== tokens.length) {\n state.env ??= {};\n state.env[ENV_FLAG_NAME] = true;\n }\n\n state.tokens = tokens;\n\n function openSection() {\n const t = new Token(TokenType.SectionOpen, 'section', 1);\n t.attrPush(['class', SectionCN.Section]);\n t.attrPush([SectionAttr.DataKey, DATA_KEY]);\n t.attrPush([SectionAttr.DataId, generateID(DATA_KEY)]);\n t.block = true;\n return t;\n }\n\n function closeSection() {\n const t = new Token(TokenType.SectionClose, 'section', -1);\n t.block = true;\n return t;\n }\n\n function openContent() {\n const t = new Token(TokenType.ContentOpen, 'div', 1);\n t.attrPush(['class', SectionCN.Content]);\n t.block = true;\n return t;\n }\n\n function closeContent() {\n const t = new Token(TokenType.ContentClose, 'div', -1);\n t.block = true;\n return t;\n }\n\n function closeSections(section: Section) {\n while (\n last(sections) &&\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n section.header <= last(sections)!.header &&\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n section.nesting <= last(sections)!.nesting\n ) {\n sections.pop();\n tokens.push(closeContent());\n tokens.push(closeSection());\n }\n }\n\n function closeSectionsToCurrentNesting(nesting: number) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n while (last(sections) && nesting < last(sections)!.nesting) {\n sections.pop();\n tokens.push(closeContent());\n tokens.push(closeSection());\n }\n }\n\n function closeAllSections() {\n while (sections.pop()) {\n tokens.push(closeContent());\n tokens.push(closeSection());\n }\n }\n };\n}\n", "export function headingLevel(header: string) {\n return parseInt(header.charAt(1), 10);\n}\n\nexport function last<T>(arr: T[]): T | undefined {\n return arr[arr.length - 1];\n}\n\nexport function hidden<B extends Record<string | symbol, unknown>, F extends string | symbol, V>(\n box: B,\n field: F,\n value: V,\n) {\n if (!(field in box)) {\n Object.defineProperty(box, field, {\n enumerable: false,\n value: value,\n });\n }\n\n return box as B & Record<F, V>;\n}\n\nexport type Runtime = {\n script: string;\n style: string;\n};\n\ndeclare const __dirname: string;\nexport function copyRuntime(\n {runtime, output}: {runtime: Runtime; output: string},\n cache: Set<string>,\n) {\n const PATH_TO_RUNTIME = '../runtime';\n const {join, resolve} = dynrequire('node:path');\n const runtimeFiles = {\n 'index.js': runtime.script,\n 'index.css': runtime.style,\n };\n for (const [originFile, outputFile] of Object.entries(runtimeFiles)) {\n const file = join(PATH_TO_RUNTIME, originFile);\n if (!cache.has(file)) {\n cache.add(file);\n copy(resolve(__dirname, file), join(output, outputFile));\n }\n }\n}\n\nexport function copy(from: string, to: string) {\n const {mkdirSync, copyFileSync} = dynrequire('node:fs');\n const {dirname} = dynrequire('node:path');\n\n mkdirSync(dirname(to), {recursive: true});\n copyFileSync(from, to);\n}\n\n/*\n * Runtime require hidden for builders.\n * Used for nodejs api\n */\nexport function dynrequire(module: string) {\n // eslint-disable-next-line no-eval\n return eval(`require('${module}')`);\n}\n", "import type MarkdownIt from 'markdown-it';\nimport type {IDGenerator} from '@diplodoc/utils';\n\nimport {headingBlockRule} from './headingBlockRule';\nimport {createSectionsCoreRule} from './sectionsCoreRule';\n\n/**\n * Creates a folding-heading plugin with an optional external ID generator.\n * When `generateID` is provided, all generated section IDs share the same counter\n * as other plugins, ensuring deterministic output regardless of --merge-includes.\n * When omitted, the plugin uses its internal fallback generator.\n *\n * @param generateID - Optional external ID generator shared with the rest of the transform pipeline.\n * @returns Markdown-it plugin that registers folding heading parsing and section wrapping rules.\n */\nexport function createFoldingHeadingPlugin(generateID?: IDGenerator) {\n return (md: MarkdownIt) => {\n md.block.ruler.at('heading', headingBlockRule, {\n alt: ['paragraph', 'reference', 'blockquote'],\n });\n md.core.ruler.push('heading_sections', createSectionsCoreRule(generateID));\n };\n}\n", "import type MarkdownIt from 'markdown-it';\nimport type {PluginWithOptions} from 'markdown-it';\nimport type {IDGenerator} from '@diplodoc/utils';\n\nimport {ENV_FLAG_NAME} from './const';\nimport {createFoldingHeadingPlugin} from './plugin';\nimport {type Runtime, copyRuntime, dynrequire, hidden} from './utils';\n\nconst registerTransform = (\n md: MarkdownIt,\n {\n runtime,\n bundle,\n output,\n generateID,\n }: Pick<NormalizedPluginOptions, 'bundle' | 'runtime'> & {\n output: string;\n generateID?: IDGenerator;\n },\n) => {\n md.use(createFoldingHeadingPlugin(generateID));\n md.core.ruler.push('heading_sections_after', ({env}) => {\n hidden(env, 'bundled', new Set<string>());\n\n if (env?.[ENV_FLAG_NAME]) {\n env.meta = env.meta || {};\n env.meta.script = env.meta.script || [];\n env.meta.script.push(runtime.script);\n env.meta.style = env.meta.style || [];\n env.meta.style.push(runtime.style);\n\n if (bundle) {\n copyRuntime({runtime, output}, env.bundled);\n }\n }\n });\n};\n\ntype NormalizedPluginOptions = Omit<TransformOptions, 'runtime'> & {\n runtime: Runtime;\n};\n\nexport type TransformOptions = {\n runtime?:\n | string\n | {\n script: string;\n style: string;\n };\n bundle?: boolean;\n};\n\ntype InputOptions = {\n destRoot: string;\n};\n\nexport function transform(options: Partial<TransformOptions> = {}) {\n const {bundle = true} = options;\n\n if (bundle && typeof options.runtime === 'string') {\n throw new TypeError('Option `runtime` should be record when `bundle` is enabled.');\n }\n\n const runtime: Runtime =\n typeof options.runtime === 'string'\n ? {script: options.runtime, style: options.runtime}\n : options.runtime || {\n script: '_assets/folding-headings-extension.js',\n style: '_assets/folding-headings-extension.css',\n };\n\n const plugin: PluginWithOptions<{output?: string; generateID?: IDGenerator}> = function (\n md: MarkdownIt,\n {output = '.', generateID} = {},\n ) {\n registerTransform(md, {\n runtime,\n bundle,\n output,\n generateID,\n });\n };\n\n Object.assign(plugin, {\n collect(input: string, {destRoot = '.'}: InputOptions) {\n const MdIt = dynrequire('markdown-it');\n const md = new MdIt().use((md: MarkdownIt) => {\n registerTransform(md, {\n runtime,\n bundle,\n output: destRoot,\n });\n });\n\n md.parse(input, {});\n },\n });\n\n return plugin;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,WAAW;AAEjB,IAAM,cAAc;AAAA,EACvB,QAAQ;AAAA,EACR,SAAS;AACb;AAEO,IAAM,YAAY;AAAA,EACrB,SAAS;AAAA,EACT,SAAS;AACb;;;ACRO,IAAM,gBAAgB;AAEtB,IAAM,YAAY;AAAA,EACrB,SAAS;AAAA,EACT,aAAa;AAAA,EACb,cAAc;AAAA,EACd,SAAS;AAAA,EACT,aAAa;AAAA,EACb,cAAc;AAAA,EACd,SAAS;AAAA,EACT,aAAa;AAAA,EACb,cAAc;AAClB;;;ACRO,IAAM,mBAA0C,CAAC,OAAO,WAAW,UAAU,WAAW;AAC3F,QAAM,EAAC,QAAO,IAAI,MAAM,GAAG;AAE3B,MAAI,MAAM,MAAM,OAAO,SAAS,IAAI,MAAM,OAAO,SAAS;AAC1D,MAAI,MAAM,MAAM,OAAO,SAAS;AAGhC,MAAI,MAAM,OAAO,SAAS,IAAI,MAAM,aAAa,GAAG;AAChD,WAAO;AAAA,EACX;AAEA,MAAI,KAAK,MAAM,IAAI,WAAW,GAAG;AAEjC,MAAI,OAAO,MAAgB,OAAO,KAAK;AACnC,WAAO;AAAA,EACX;AAGA,MAAI,QAAQ;AACZ,OAAK,MAAM,IAAI,WAAW,EAAE,GAAG;AAC/B,SAAO,OAAO,MAAgB,MAAM,OAAO,SAAS,GAAG;AACnD;AACA,SAAK,MAAM,IAAI,WAAW,EAAE,GAAG;AAAA,EACnC;AAEA,MAAI,UAAU;AACd,MAAI,OAAO,IAAc;AACrB,cAAU;AACV,SAAK,MAAM,IAAI,WAAW,EAAE,GAAG;AAAA,EACnC;AAEA,MAAI,QAAQ,KAAM,MAAM,OAAO,CAAC,QAAQ,EAAE,GAAI;AAC1C,WAAO;AAAA,EACX;AAEA,MAAI,QAAQ;AACR,WAAO;AAAA,EACX;AAIA,QAAM,MAAM,eAAe,KAAK,GAAG;AACnC,QAAM,MAAM,MAAM,cAAc,KAAK,IAAM,GAAG;AAC9C,MAAI,MAAM,OAAO,QAAQ,MAAM,IAAI,WAAW,MAAM,CAAC,CAAC,GAAG;AACrD,UAAM;AAAA,EACV;AAEA,QAAM,OAAO,YAAY;AAEzB,MAAI,QAAQ,MAAM,KAAK,UAAU,aAAa,MAAM,OAAO,KAAK,GAAG,CAAC;AACpE,QAAM,SAAS,WAAW,MAAM,GAAG,KAAK,KAAK,UAAU,MAAM;AAC7D,QAAM,MAAM,CAAC,WAAW,MAAM,IAAI;AAClC,MAAI,SAAS;AACT,UAAM,SAAS,CAAC;AAChB,UAAM,KAAK,UAAU;AAAA,EACzB;AAEA,UAAQ,MAAM,KAAK,UAAU,IAAI,CAAC;AAClC,QAAM,UAAU,MAAM,IAAI,MAAM,KAAK,GAAG,EAAE,KAAK;AAC/C,QAAM,MAAM,CAAC,WAAW,MAAM,IAAI;AAClC,QAAM,WAAW,CAAC;AAElB,UAAQ,MAAM,KAAK,UAAU,cAAc,MAAM,OAAO,KAAK,GAAG,EAAE;AAClE,QAAM,SAAS,WAAW,MAAM,GAAG,KAAK,KAAK,UAAU,MAAM;AAC7D,MAAI,SAAS;AACT,UAAM,SAAS,CAAC;AAChB,UAAM,KAAK,UAAU;AAAA,EACzB;AAEA,SAAO;AACX;;;ACzEA,mBAA0C;;;ACHnC,SAAS,aAAa,QAAgB;AACzC,SAAO,SAAS,OAAO,OAAO,CAAC,GAAG,EAAE;AACxC;AAEO,SAAS,KAAQ,KAAyB;AAC7C,SAAO,IAAI,IAAI,SAAS,CAAC;AAC7B;AAEO,SAAS,OACZ,KACA,OACA,OACF;AACE,MAAI,EAAE,SAAS,MAAM;AACjB,WAAO,eAAe,KAAK,OAAO;AAAA,MAC9B,YAAY;AAAA,MACZ;AAAA,IACJ,CAAC;AAAA,EACL;AAEA,SAAO;AACX;AAQO,SAAS,YACZ,EAAC,SAAS,OAAM,GAChB,OACF;AACE,QAAM,kBAAkB;AACxB,QAAM,EAAC,MAAM,QAAO,IAAI,WAAW,WAAW;AAC9C,QAAM,eAAe;AAAA,IACjB,YAAY,QAAQ;AAAA,IACpB,aAAa,QAAQ;AAAA,EACzB;AACA,aAAW,CAAC,YAAY,UAAU,KAAK,OAAO,QAAQ,YAAY,GAAG;AACjE,UAAM,OAAO,KAAK,iBAAiB,UAAU;AAC7C,QAAI,CAAC,MAAM,IAAI,IAAI,GAAG;AAClB,YAAM,IAAI,IAAI;AACd,WAAK,QAAQ,WAAW,IAAI,GAAG,KAAK,QAAQ,UAAU,CAAC;AAAA,IAC3D;AAAA,EACJ;AACJ;AAEO,SAAS,KAAK,MAAc,IAAY;AAC3C,QAAM,EAAC,WAAW,aAAY,IAAI,WAAW,SAAS;AACtD,QAAM,EAAC,QAAO,IAAI,WAAW,WAAW;AAExC,YAAU,QAAQ,EAAE,GAAG,EAAC,WAAW,KAAI,CAAC;AACxC,eAAa,MAAM,EAAE;AACzB;AAMO,SAAS,WAAW,QAAgB;AAEvC,SAAO,KAAK,YAAY,MAAM,IAAI;AACtC;;;AD9CO,SAAS,uBAAuB,oBAAiD;AAGpF,QAAM,aACF,0BAAuB,0CAA4B,QAAQ;AAE/D,SAAO,CAAC,UAAU;AACd,UAAM,QAAQ,MAAM;AACpB,UAAM,SAA8B,CAAC;AACrC,UAAM,WAAsB,CAAC;AAC7B,QAAI,cAAc;AAElB,eAAW,SAAS,MAAM,QAAQ;AAE9B,UAAI,MAAM,KAAK,OAAO,UAAU,OAAO,MAAM,GAAG;AAC5C,uBAAe,MAAM;AAAA,MACzB;AAEA,UAAI,KAAK,QAAQ,KAAK,cAAc,KAAK,QAAQ,EAAG,SAAS;AACzD,sCAA8B,WAAW;AAAA,MAC7C;AAEA,YAAM,aAAa,MAAM,OAAO,SAAS,IAAI;AAG7C,UAAI,MAAM,SAAS,UAAU,aAAa;AACtC,cAAM,UAAmB;AAAA,UACrB,QAAQ,aAAa,MAAM,GAAG;AAAA,UAC9B,SAAS;AAAA,QACb;AACA,sBAAc,OAAO;AACrB,YAAI,YAAY;AACZ,iBAAO,KAAK,YAAY,CAAC;AACzB,mBAAS,KAAK,OAAO;AAAA,QACzB;AAAA,MACJ;AAEA,aAAO,KAAK,KAAK;AAEjB,UAAI,MAAM,SAAS,UAAU,gBAAgB,YAAY;AACrD,eAAO,KAAK,YAAY,CAAC;AAAA,MAC7B;AAAA,IACJ;AAGA,qBAAiB;AAEjB,QAAI,MAAM,OAAO,WAAW,OAAO,QAAQ;AACvC,YAAM,QAAQ,CAAC;AACf,YAAM,IAAI,aAAa,IAAI;AAAA,IAC/B;AAEA,UAAM,SAAS;AAEf,aAAS,cAAc;AACnB,YAAM,IAAI,IAAI,MAAM,UAAU,aAAa,WAAW,CAAC;AACvD,QAAE,SAAS,CAAC,SAAS,UAAU,OAAO,CAAC;AACvC,QAAE,SAAS,CAAC,YAAY,SAAS,QAAQ,CAAC;AAC1C,QAAE,SAAS,CAAC,YAAY,QAAQ,WAAW,QAAQ,CAAC,CAAC;AACrD,QAAE,QAAQ;AACV,aAAO;AAAA,IACX;AAEA,aAAS,eAAe;AACpB,YAAM,IAAI,IAAI,MAAM,UAAU,cAAc,WAAW,EAAE;AACzD,QAAE,QAAQ;AACV,aAAO;AAAA,IACX;AAEA,aAAS,cAAc;AACnB,YAAM,IAAI,IAAI,MAAM,UAAU,aAAa,OAAO,CAAC;AACnD,QAAE,SAAS,CAAC,SAAS,UAAU,OAAO,CAAC;AACvC,QAAE,QAAQ;AACV,aAAO;AAAA,IACX;AAEA,aAAS,eAAe;AACpB,YAAM,IAAI,IAAI,MAAM,UAAU,cAAc,OAAO,EAAE;AACrD,QAAE,QAAQ;AACV,aAAO;AAAA,IACX;AAEA,aAAS,cAAc,SAAkB;AACrC,aACI,KAAK,QAAQ;AAAA,MAEb,QAAQ,UAAU,KAAK,QAAQ,EAAG;AAAA,MAElC,QAAQ,WAAW,KAAK,QAAQ,EAAG,SACrC;AACE,iBAAS,IAAI;AACb,eAAO,KAAK,aAAa,CAAC;AAC1B,eAAO,KAAK,aAAa,CAAC;AAAA,MAC9B;AAAA,IACJ;AAEA,aAAS,8BAA8B,SAAiB;AAEpD,aAAO,KAAK,QAAQ,KAAK,UAAU,KAAK,QAAQ,EAAG,SAAS;AACxD,iBAAS,IAAI;AACb,eAAO,KAAK,aAAa,CAAC;AAC1B,eAAO,KAAK,aAAa,CAAC;AAAA,MAC9B;AAAA,IACJ;AAEA,aAAS,mBAAmB;AACxB,aAAO,SAAS,IAAI,GAAG;AACnB,eAAO,KAAK,aAAa,CAAC;AAC1B,eAAO,KAAK,aAAa,CAAC;AAAA,MAC9B;AAAA,IACJ;AAAA,EACJ;AACJ;;;AElHO,SAAS,2BAA2B,YAA0B;AACjE,SAAO,CAAC,OAAmB;AACvB,OAAG,MAAM,MAAM,GAAG,WAAW,kBAAkB;AAAA,MAC3C,KAAK,CAAC,aAAa,aAAa,YAAY;AAAA,IAChD,CAAC;AACD,OAAG,KAAK,MAAM,KAAK,oBAAoB,uBAAuB,UAAU,CAAC;AAAA,EAC7E;AACJ;;;ACdA,IAAM,oBAAoB,CACtB,IACA;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ,MAIC;AACD,KAAG,IAAI,2BAA2B,UAAU,CAAC;AAC7C,KAAG,KAAK,MAAM,KAAK,0BAA0B,CAAC,EAAC,IAAG,MAAM;AACpD,WAAO,KAAK,WAAW,oBAAI,IAAY,CAAC;AAExC,QAAI,MAAM,aAAa,GAAG;AACtB,UAAI,OAAO,IAAI,QAAQ,CAAC;AACxB,UAAI,KAAK,SAAS,IAAI,KAAK,UAAU,CAAC;AACtC,UAAI,KAAK,OAAO,KAAK,QAAQ,MAAM;AACnC,UAAI,KAAK,QAAQ,IAAI,KAAK,SAAS,CAAC;AACpC,UAAI,KAAK,MAAM,KAAK,QAAQ,KAAK;AAEjC,UAAI,QAAQ;AACR,oBAAY,EAAC,SAAS,OAAM,GAAG,IAAI,OAAO;AAAA,MAC9C;AAAA,IACJ;AAAA,EACJ,CAAC;AACL;AAoBO,SAAS,UAAU,UAAqC,CAAC,GAAG;AAC/D,QAAM,EAAC,SAAS,KAAI,IAAI;AAExB,MAAI,UAAU,OAAO,QAAQ,YAAY,UAAU;AAC/C,UAAM,IAAI,UAAU,6DAA6D;AAAA,EACrF;AAEA,QAAM,UACF,OAAO,QAAQ,YAAY,WACrB,EAAC,QAAQ,QAAQ,SAAS,OAAO,QAAQ,QAAO,IAChD,QAAQ,WAAW;AAAA,IACf,QAAQ;AAAA,IACR,OAAO;AAAA,EACX;AAEV,QAAM,SAAyE,SAC3E,IACA,EAAC,SAAS,KAAK,WAAU,IAAI,CAAC,GAChC;AACE,sBAAkB,IAAI;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ,CAAC;AAAA,EACL;AAEA,SAAO,OAAO,QAAQ;AAAA,IAClB,QAAQ,OAAe,EAAC,WAAW,IAAG,GAAiB;AACnD,YAAM,OAAO,WAAW,aAAa;AACrC,YAAM,KAAK,IAAI,KAAK,EAAE,IAAI,CAACA,QAAmB;AAC1C,0BAAkBA,KAAI;AAAA,UAClB;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,QACZ,CAAC;AAAA,MACL,CAAC;AAED,SAAG,MAAM,OAAO,CAAC,CAAC;AAAA,IACtB;AAAA,EACJ,CAAC;AAED,SAAO;AACX;",
|
|
6
6
|
"names": ["md"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,12 @@
|
|
|
1
|
-
import type
|
|
2
|
-
|
|
1
|
+
import type MarkdownIt from 'markdown-it';
|
|
2
|
+
import type { IDGenerator } from '@diplodoc/utils';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a folding-heading plugin with an optional external ID generator.
|
|
5
|
+
* When `generateID` is provided, all generated section IDs share the same counter
|
|
6
|
+
* as other plugins, ensuring deterministic output regardless of --merge-includes.
|
|
7
|
+
* When omitted, the plugin uses its internal fallback generator.
|
|
8
|
+
*
|
|
9
|
+
* @param generateID - Optional external ID generator shared with the rest of the transform pipeline.
|
|
10
|
+
* @returns Markdown-it plugin that registers folding heading parsing and section wrapping rules.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createFoldingHeadingPlugin(generateID?: IDGenerator): (md: MarkdownIt) => void;
|
|
@@ -1,2 +1,10 @@
|
|
|
1
1
|
import type Core from 'markdown-it/lib/parser_core';
|
|
2
|
-
|
|
2
|
+
import type { IDGenerator } from '@diplodoc/utils';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a core rule that wraps folding headings in `<section>` elements with unique IDs.
|
|
5
|
+
* @param externalGenerateID - Optional external ID generator (e.g. from MarkdownItPluginOpts).
|
|
6
|
+
* When provided, ensures all plugins share the same per-file generator.
|
|
7
|
+
* When omitted, uses random fallback behavior.
|
|
8
|
+
* @returns Markdown-it core rule that injects section wrapper tokens around folding headings.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createSectionsCoreRule(externalGenerateID?: IDGenerator): Core.RuleCore;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type MarkdownIt from 'markdown-it';
|
|
2
|
+
import type { IDGenerator } from '@diplodoc/utils';
|
|
2
3
|
export type TransformOptions = {
|
|
3
4
|
runtime?: string | {
|
|
4
5
|
script: string;
|
|
@@ -8,4 +9,5 @@ export type TransformOptions = {
|
|
|
8
9
|
};
|
|
9
10
|
export declare function transform(options?: Partial<TransformOptions>): MarkdownIt.PluginWithOptions<{
|
|
10
11
|
output?: string;
|
|
12
|
+
generateID?: IDGenerator;
|
|
11
13
|
}>;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export declare function generateID(): string;
|
|
2
1
|
export declare function headingLevel(header: string): number;
|
|
3
2
|
export declare function last<T>(arr: T[]): T | undefined;
|
|
4
3
|
export declare function hidden<B extends Record<string | symbol, unknown>, F extends string | symbol, V>(box: B, field: F, value: V): B & Record<F, V>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diplodoc/folding-headings-extension",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Folding headings extension for Diplodoc platform ",
|
|
5
5
|
"main": "build/plugin/index.js",
|
|
6
6
|
"types": "build/plugin/index.d.ts",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@diplodoc/lint": "^1.14.1",
|
|
51
51
|
"@diplodoc/tsconfig": "^1.0.2",
|
|
52
|
+
"@diplodoc/utils": "^2.2.2",
|
|
52
53
|
"@types/markdown-it": "^13.0.9",
|
|
53
54
|
"@vitest/coverage-v8": "^3.2.4",
|
|
54
55
|
"markdown-it": "^13.0.0",
|