@diplodoc/folding-headings-extension 0.1.3 → 0.2.1

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.
@@ -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
- var sectionsCoreRule = (state) => {
154
- const Token = state.Token;
155
- const tokens = [];
156
- const sections = [];
157
- let nestedLevel = 0;
158
- for (const token of state.tokens) {
159
- if (token.type.search(TokenType.Heading) !== 0) {
160
- nestedLevel += token.nesting;
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
- if (last(sections) && nestedLevel < last(sections).nesting) {
163
- closeSectionsToCurrentNesting(nestedLevel);
184
+ closeAllSections();
185
+ if (state.tokens.length !== tokens.length) {
186
+ state.env ??= {};
187
+ state.env[ENV_FLAG_NAME] = true;
164
188
  }
165
- const hasFolding = token.markup.endsWith("#+");
166
- if (token.type === TokenType.HeadingOpen) {
167
- const section = {
168
- header: headingLevel(token.tag),
169
- nesting: nestedLevel
170
- };
171
- closeSections(section);
172
- if (hasFolding) {
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
- tokens.push(token);
178
- if (token.type === TokenType.HeadingClose && hasFolding) {
179
- tokens.push(openContent());
198
+ function closeSection() {
199
+ const t = new Token(TokenType.SectionClose, "section", -1);
200
+ t.block = true;
201
+ return t;
180
202
  }
181
- }
182
- closeAllSections();
183
- if (state.tokens.length !== tokens.length) {
184
- state.env ??= {};
185
- state.env[ENV_FLAG_NAME] = true;
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
- function closeSectionsToCurrentNesting(nesting) {
222
- while (last(sections) && nesting < last(sections).nesting) {
223
- sections.pop();
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
- function closeAllSections() {
229
- while (sections.pop()) {
230
- tokens.push(closeContent());
231
- tokens.push(closeSection());
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
- var foldingHeadingPlugin = (md) => {
238
- md.block.ruler.at("heading", headingBlockRule, { alt: ["paragraph", "reference", "blockquote"] });
239
- md.core.ruler.push("heading_sections", sectionsCoreRule);
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(foldingHeadingPlugin);
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/utils.ts", "../../src/plugin/sectionsCoreRule.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 {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": "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",
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": "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",
6
6
  "names": ["md"]
7
7
  }
@@ -1,2 +1,12 @@
1
- import type { PluginSimple } from 'markdown-it';
2
- export declare const foldingHeadingPlugin: PluginSimple;
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
- export declare const sectionsCoreRule: Core.RuleCore;
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.1.3",
3
+ "version": "0.2.1",
4
4
  "description": "Folding headings extension for Diplodoc platform ",
5
5
  "main": "build/plugin/index.js",
6
6
  "types": "build/plugin/index.d.ts",
@@ -41,19 +41,20 @@
41
41
  "test:watch": "vitest --config vitest.config.mjs",
42
42
  "test:coverage": "vitest run --coverage",
43
43
  "typecheck": "tsc --noEmit",
44
- "lint": "lint update && lint",
45
- "lint:fix": "lint update && lint fix",
46
- "pre-commit": "lint update && lint-staged",
47
- "prepare": "husky"
44
+ "lint": "lint",
45
+ "lint:fix": "lint fix",
46
+ "pre-commit": "lint-staged",
47
+ "prepare": "husky || true"
48
48
  },
49
49
  "devDependencies": {
50
- "@diplodoc/lint": "^1.14.1",
51
50
  "@diplodoc/tsconfig": "^1.0.2",
51
+ "@diplodoc/utils": "^2.2.2",
52
52
  "@types/markdown-it": "^13.0.9",
53
53
  "@vitest/coverage-v8": "^3.2.4",
54
54
  "markdown-it": "^13.0.0",
55
55
  "npm-run-all": "^4.1.5",
56
56
  "typescript": "^5.3.3",
57
- "vitest": "^3.2.4"
57
+ "vitest": "^3.2.4",
58
+ "@diplodoc/infra": "2.0.2"
58
59
  }
59
60
  }