diff --git a/.eslintrc.js b/.eslintrc.js index 17eff79121..502c615068 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -298,7 +298,7 @@ module.exports = { 'jest/expect-expect': OFF, 'jest/no-large-snapshots': [ WARNING, - {maxSize: Infinity, inlineMaxSize: 10}, + {maxSize: Infinity, inlineMaxSize: 50}, ], 'jest/no-test-return-statement': ERROR, 'jest/prefer-expect-resolves': WARNING, diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/authorsSocials.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/authorsSocials.test.ts index 9a1a256587..9bc8afaf2c 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/authorsSocials.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/authorsSocials.test.ts @@ -23,7 +23,6 @@ describe('normalizeSocials', () => { mastodon: 'Mastodon', }; - // eslint-disable-next-line jest/no-large-snapshots expect(normalizeSocials(socials)).toMatchInlineSnapshot(` { "bluesky": "https://bsky.app/profile/gingergeek.co.uk", diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/validation.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/validation.test.ts index 6620705ff7..47055ffce7 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/validation.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/validation.test.ts @@ -42,19 +42,16 @@ describe('validateSidebars', () => { }); it('sidebar category wrong label', () => { - expect( - () => - validateSidebars({ - docs: [ - { - type: 'category', - label: true, - items: [{type: 'doc', id: 'doc1'}], - }, - ], - }), - - // eslint-disable-next-line jest/no-large-snapshots + expect(() => + validateSidebars({ + docs: [ + { + type: 'category', + label: true, + items: [{type: 'doc', id: 'doc1'}], + }, + ], + }), ).toThrowErrorMatchingInlineSnapshot(` "{ "type": "category", diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap b/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap deleted file mode 100644 index 9c3d5cb015..0000000000 --- a/packages/docusaurus-theme-common/src/utils/__tests__/__snapshots__/codeBlockUtils.test.ts.snap +++ /dev/null @@ -1,357 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`getLineNumbersStart handles metadata combined with other options set as flag 1`] = `1`; - -exports[`getLineNumbersStart handles metadata combined with other options set with number 1`] = `10`; - -exports[`getLineNumbersStart handles metadata standalone set as flag 1`] = `1`; - -exports[`getLineNumbersStart handles metadata standalone set with number 1`] = `10`; - -exports[`getLineNumbersStart handles prop combined with metastring set to false 1`] = `undefined`; - -exports[`getLineNumbersStart handles prop combined with metastring set to number 1`] = `10`; - -exports[`getLineNumbersStart handles prop combined with metastring set to true 1`] = `1`; - -exports[`getLineNumbersStart handles prop standalone set to false 1`] = `undefined`; - -exports[`getLineNumbersStart handles prop standalone set to number 1`] = `10`; - -exports[`getLineNumbersStart handles prop standalone set to true 1`] = `1`; - -exports[`getLineNumbersStart with nothing set 1`] = `undefined`; - -exports[`getLineNumbersStart with nothing set 2`] = `undefined`; - -exports[`parseLines does not parse content with metastring 1`] = ` -{ - "code": "aaaaa -nnnnn", - "lineClassNames": { - "0": [ - "theme-code-block-highlighted-line", - ], - }, -} -`; - -exports[`parseLines does not parse content with metastring 2`] = ` -{ - "code": "// highlight-next-line -aaaaa -bbbbb", - "lineClassNames": { - "0": [ - "theme-code-block-highlighted-line", - ], - }, -} -`; - -exports[`parseLines does not parse content with metastring 3`] = ` -{ - "code": "aaaaa -bbbbb", - "lineClassNames": { - "0": [ - "theme-code-block-highlighted-line", - ], - }, -} -`; - -exports[`parseLines does not parse content with no language 1`] = ` -{ - "code": "// highlight-next-line -aaaaa -bbbbb", - "lineClassNames": {}, -} -`; - -exports[`parseLines handles CRLF line breaks with highlight comments correctly 1`] = ` -{ - "code": "aaaaa -bbbbb", - "lineClassNames": { - "1": [ - "theme-code-block-highlighted-line", - ], - }, -} -`; - -exports[`parseLines handles CRLF line breaks with highlight metastring 1`] = ` -{ - "code": "aaaaa -bbbbb", - "lineClassNames": { - "1": [ - "theme-code-block-highlighted-line", - ], - }, -} -`; - -exports[`parseLines handles one line with multiple class names 1`] = ` -{ - "code": " -highlighted and collapsed -highlighted and collapsed -highlighted and collapsed -Only highlighted -Only collapsed -highlighted and collapsed -highlighted and collapsed -Only collapsed -highlighted and collapsed", - "lineClassNames": { - "1": [ - "highlight", - "collapse", - ], - "2": [ - "highlight", - "collapse", - ], - "3": [ - "highlight", - "collapse", - ], - "4": [ - "highlight", - ], - "5": [ - "collapse", - ], - "6": [ - "highlight", - "collapse", - ], - "7": [ - "highlight", - "collapse", - ], - "8": [ - "collapse", - ], - "9": [ - "highlight", - "collapse", - ], - }, -} -`; - -exports[`parseLines handles one line with multiple class names 2`] = ` -{ - "code": "line -line", - "lineClassNames": { - "0": [ - "a", - "b", - "c", - "d", - ], - "1": [ - "b", - "d", - ], - }, -} -`; - -exports[`parseLines parses multiple types of magic comments 1`] = ` -{ - "code": " -highlighted -collapsed -collapsed -collapsed", - "lineClassNames": { - "1": [ - "highlight", - ], - "2": [ - "collapse", - ], - "3": [ - "collapse", - ], - "4": [ - "collapse", - ], - }, -} -`; - -exports[`parseLines removes lines correctly 1`] = ` -{ - "code": "aaaaa -bbbbb", - "lineClassNames": { - "0": [ - "theme-code-block-highlighted-line", - ], - }, -} -`; - -exports[`parseLines removes lines correctly 2`] = ` -{ - "code": "aaaaa -bbbbb", - "lineClassNames": { - "0": [ - "theme-code-block-highlighted-line", - ], - }, -} -`; - -exports[`parseLines removes lines correctly 3`] = ` -{ - "code": "aaaaa -bbbbbbb -bbbbb", - "lineClassNames": { - "0": [ - "theme-code-block-highlighted-line", - "theme-code-block-highlighted-line", - ], - "1": [ - "theme-code-block-highlighted-line", - ], - "2": [ - "theme-code-block-highlighted-line", - ], - }, -} -`; - -exports[`parseLines respects language: html 1`] = ` -{ - "code": "aaaa -{/* highlight-next-line */} -bbbbb -dddd", - "lineClassNames": { - "0": [ - "theme-code-block-highlighted-line", - ], - "3": [ - "theme-code-block-highlighted-line", - ], - }, -} -`; - -exports[`parseLines respects language: js 1`] = ` -{ - "code": "# highlight-next-line -aaaaa -bbbbb", - "lineClassNames": {}, -} -`; - -exports[`parseLines respects language: jsx 1`] = ` -{ - "code": "aaaa -bbbbb - -dddd", - "lineClassNames": { - "0": [ - "theme-code-block-highlighted-line", - ], - "1": [ - "theme-code-block-highlighted-line", - ], - }, -} -`; - -exports[`parseLines respects language: md 1`] = ` -{ - "code": "--- -aaa: boo ---- - -aaaa - -
-foo -
- -bbbbb -dddd - -\`\`\`js -// highlight-next-line -console.log("preserved"); -\`\`\`", - "lineClassNames": { - "1": [ - "theme-code-block-highlighted-line", - ], - "11": [ - "theme-code-block-highlighted-line", - ], - "7": [ - "theme-code-block-highlighted-line", - ], - }, -} -`; - -exports[`parseLines respects language: none 1`] = ` -{ - "code": "aaaa -bbbbb -ccccc -dddd", - "lineClassNames": { - "0": [ - "theme-code-block-highlighted-line", - ], - "1": [ - "theme-code-block-highlighted-line", - ], - "2": [ - "theme-code-block-highlighted-line", - ], - "3": [ - "theme-code-block-highlighted-line", - ], - }, -} -`; - -exports[`parseLines respects language: py 1`] = ` -{ - "code": "/* highlight-next-line */ -aaaaa -bbbbb", - "lineClassNames": {}, -} -`; - -exports[`parseLines respects language: py 2`] = ` -{ - "code": "// highlight-next-line -aaaa -/* highlight-next-line */ -bbbbb -ccccc - -dddd", - "lineClassNames": { - "4": [ - "theme-code-block-highlighted-line", - ], - }, -} -`; diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts b/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts index b3a47f00d7..f439e59e67 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts +++ b/packages/docusaurus-theme-common/src/utils/__tests__/codeBlockUtils.test.ts @@ -84,7 +84,18 @@ describe('parseLines', () => { language: 'js', magicComments: defaultMagicComments, }), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(` + { + "code": "aaaaa + nnnnn", + "lineClassNames": { + "0": [ + "theme-code-block-highlighted-line", + ], + }, + } + `); + expect( parseLines( `// highlight-next-line @@ -96,7 +107,19 @@ bbbbb`, magicComments: defaultMagicComments, }, ), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(` + { + "code": "// highlight-next-line + aaaaa + bbbbb", + "lineClassNames": { + "0": [ + "theme-code-block-highlighted-line", + ], + }, + } + `); + expect( parseLines( `aaaaa @@ -107,7 +130,18 @@ bbbbb`, magicComments: defaultMagicComments, }, ), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(` + { + "code": "aaaaa + bbbbb", + "lineClassNames": { + "0": [ + "theme-code-block-highlighted-line", + ], + }, + } + `); + expect(() => parseLines( `aaaaa @@ -122,6 +156,7 @@ bbbbb`, `"A highlight range has been given in code block's metastring (\`\`\` {1}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges."`, ); }); + it('does not parse content with no language', () => { expect( parseLines( @@ -134,8 +169,16 @@ bbbbb`, magicComments: defaultMagicComments, }, ), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(` + { + "code": "// highlight-next-line + aaaaa + bbbbb", + "lineClassNames": {}, + } + `); }); + it('removes lines correctly', () => { expect( parseLines( @@ -144,7 +187,18 @@ aaaaa bbbbb`, {metastring: '', language: 'js', magicComments: defaultMagicComments}, ), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(` + { + "code": "aaaaa + bbbbb", + "lineClassNames": { + "0": [ + "theme-code-block-highlighted-line", + ], + }, + } + `); + expect( parseLines( `// highlight-start @@ -153,7 +207,18 @@ aaaaa bbbbb`, {metastring: '', language: 'js', magicComments: defaultMagicComments}, ), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(` + { + "code": "aaaaa + bbbbb", + "lineClassNames": { + "0": [ + "theme-code-block-highlighted-line", + ], + }, + } + `); + expect( parseLines( `// highlight-start @@ -165,8 +230,27 @@ bbbbbbb bbbbb`, {metastring: '', language: 'js', magicComments: defaultMagicComments}, ), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(` + { + "code": "aaaaa + bbbbbbb + bbbbb", + "lineClassNames": { + "0": [ + "theme-code-block-highlighted-line", + "theme-code-block-highlighted-line", + ], + "1": [ + "theme-code-block-highlighted-line", + ], + "2": [ + "theme-code-block-highlighted-line", + ], + }, + } + `); }); + it('respects language', () => { expect( parseLines( @@ -175,7 +259,15 @@ aaaaa bbbbb`, {metastring: '', language: 'js', magicComments: defaultMagicComments}, ), - ).toMatchSnapshot('js'); + ).toMatchInlineSnapshot(` + { + "code": "# highlight-next-line + aaaaa + bbbbb", + "lineClassNames": {}, + } + `); + expect( parseLines( `/* highlight-next-line */ @@ -183,7 +275,15 @@ aaaaa bbbbb`, {metastring: '', language: 'py', magicComments: defaultMagicComments}, ), - ).toMatchSnapshot('py'); + ).toMatchInlineSnapshot(` + { + "code": "/* highlight-next-line */ + aaaaa + bbbbb", + "lineClassNames": {}, + } + `); + expect( parseLines( `// highlight-next-line @@ -196,7 +296,23 @@ ccccc dddd`, {metastring: '', language: 'py', magicComments: defaultMagicComments}, ), - ).toMatchSnapshot('py'); + ).toMatchInlineSnapshot(` + { + "code": "// highlight-next-line + aaaa + /* highlight-next-line */ + bbbbb + ccccc + + dddd", + "lineClassNames": { + "4": [ + "theme-code-block-highlighted-line", + ], + }, + } + `); + expect( parseLines( `// highlight-next-line @@ -209,7 +325,29 @@ ccccc dddd`, {metastring: '', language: '', magicComments: defaultMagicComments}, ), - ).toMatchSnapshot('none'); + ).toMatchInlineSnapshot(` + { + "code": "aaaa + bbbbb + ccccc + dddd", + "lineClassNames": { + "0": [ + "theme-code-block-highlighted-line", + ], + "1": [ + "theme-code-block-highlighted-line", + ], + "2": [ + "theme-code-block-highlighted-line", + ], + "3": [ + "theme-code-block-highlighted-line", + ], + }, + } + `); + expect( parseLines( `// highlight-next-line @@ -220,7 +358,23 @@ bbbbb dddd`, {metastring: '', language: 'jsx', magicComments: defaultMagicComments}, ), - ).toMatchSnapshot('jsx'); + ).toMatchInlineSnapshot(` + { + "code": "aaaa + bbbbb + + dddd", + "lineClassNames": { + "0": [ + "theme-code-block-highlighted-line", + ], + "1": [ + "theme-code-block-highlighted-line", + ], + }, + } + `); + expect( parseLines( `// highlight-next-line @@ -231,7 +385,23 @@ bbbbb dddd`, {metastring: '', language: 'html', magicComments: defaultMagicComments}, ), - ).toMatchSnapshot('html'); + ).toMatchInlineSnapshot(` + { + "code": "aaaa + {/* highlight-next-line */} + bbbbb + dddd", + "lineClassNames": { + "0": [ + "theme-code-block-highlighted-line", + ], + "3": [ + "theme-code-block-highlighted-line", + ], + }, + } + `); + expect( parseLines( `--- @@ -257,7 +427,38 @@ console.log("preserved"); `, {metastring: '', language: 'md', magicComments: defaultMagicComments}, ), - ).toMatchSnapshot('md'); + ).toMatchInlineSnapshot(` + { + "code": "--- + aaa: boo + --- + + aaaa + +
+ foo +
+ + bbbbb + dddd + + \`\`\`js + // highlight-next-line + console.log("preserved"); + \`\`\`", + "lineClassNames": { + "1": [ + "theme-code-block-highlighted-line", + ], + "11": [ + "theme-code-block-highlighted-line", + ], + "7": [ + "theme-code-block-highlighted-line", + ], + }, + } + `); }); it('parses multiple types of magic comments', () => { @@ -290,7 +491,29 @@ collapsed ], }, ), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(` + { + "code": " + highlighted + collapsed + collapsed + collapsed", + "lineClassNames": { + "1": [ + "highlight", + ], + "2": [ + "collapse", + ], + "3": [ + "collapse", + ], + "4": [ + "collapse", + ], + }, + } + `); }); it('handles one line with multiple class names', () => { @@ -335,7 +558,56 @@ highlighted and collapsed ], }, ), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(` + { + "code": " + highlighted and collapsed + highlighted and collapsed + highlighted and collapsed + Only highlighted + Only collapsed + highlighted and collapsed + highlighted and collapsed + Only collapsed + highlighted and collapsed", + "lineClassNames": { + "1": [ + "highlight", + "collapse", + ], + "2": [ + "highlight", + "collapse", + ], + "3": [ + "highlight", + "collapse", + ], + "4": [ + "highlight", + ], + "5": [ + "collapse", + ], + "6": [ + "highlight", + "collapse", + ], + "7": [ + "highlight", + "collapse", + ], + "8": [ + "collapse", + ], + "9": [ + "highlight", + "collapse", + ], + }, + } + `); + expect( parseLines( `// a @@ -358,7 +630,24 @@ line ], }, ), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(` + { + "code": "line + line", + "lineClassNames": { + "0": [ + "a", + "b", + "c", + "d", + ], + "1": [ + "b", + "d", + ], + }, + } + `); }); it('handles CRLF line breaks with highlight comments correctly', () => { @@ -371,7 +660,17 @@ line magicComments: defaultMagicComments, }, ), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(` + { + "code": "aaaaa + bbbbb", + "lineClassNames": { + "1": [ + "theme-code-block-highlighted-line", + ], + }, + } + `); }); it('handles CRLF line breaks with highlight metastring', () => { @@ -381,7 +680,17 @@ line language: 'js', magicComments: defaultMagicComments, }), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(` + { + "code": "aaaaa + bbbbb", + "lineClassNames": { + "1": [ + "theme-code-block-highlighted-line", + ], + }, + } + `); }); }); @@ -392,13 +701,13 @@ describe('getLineNumbersStart', () => { showLineNumbers: undefined, metastring: undefined, }), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(`undefined`); expect( getLineNumbersStart({ showLineNumbers: undefined, metastring: '', }), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(`undefined`); }); describe('handles prop', () => { @@ -409,7 +718,7 @@ describe('getLineNumbersStart', () => { showLineNumbers: true, metastring: 'showLineNumbers=2', }), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(`1`); }); it('set to false', () => { @@ -418,7 +727,7 @@ describe('getLineNumbersStart', () => { showLineNumbers: false, metastring: 'showLineNumbers=2', }), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(`undefined`); }); it('set to number', () => { @@ -427,7 +736,7 @@ describe('getLineNumbersStart', () => { showLineNumbers: 10, metastring: 'showLineNumbers=2', }), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(`10`); }); }); @@ -438,7 +747,7 @@ describe('getLineNumbersStart', () => { showLineNumbers: true, metastring: undefined, }), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(`1`); }); it('set to false', () => { @@ -447,7 +756,7 @@ describe('getLineNumbersStart', () => { showLineNumbers: false, metastring: undefined, }), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(`undefined`); }); it('set to number', () => { @@ -456,7 +765,7 @@ describe('getLineNumbersStart', () => { showLineNumbers: 10, metastring: undefined, }), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(`10`); }); }); }); @@ -469,7 +778,7 @@ describe('getLineNumbersStart', () => { showLineNumbers: undefined, metastring: 'showLineNumbers', }), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(`1`); }); it('set with number', () => { expect( @@ -477,7 +786,7 @@ describe('getLineNumbersStart', () => { showLineNumbers: undefined, metastring: 'showLineNumbers=10', }), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(`10`); }); }); @@ -488,7 +797,7 @@ describe('getLineNumbersStart', () => { showLineNumbers: undefined, metastring: '{1,2-3} title="file.txt" showLineNumbers noInline', }), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(`1`); }); it('set with number', () => { expect( @@ -496,7 +805,7 @@ describe('getLineNumbersStart', () => { showLineNumbers: undefined, metastring: '{1,2-3} title="file.txt" showLineNumbers=10 noInline', }), - ).toMatchSnapshot(); + ).toMatchInlineSnapshot(`10`); }); }); }); diff --git a/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts b/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts index 548a5dc0ba..56acec8fe3 100644 --- a/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts @@ -196,53 +196,45 @@ export function parseLanguage(className: string): string | undefined { return languageClassName?.replace(/language-/, ''); } -/** - * Parses the code content, strips away any magic comments, and returns the - * clean content and the highlighted lines marked by the comments or metastring. - * - * If the metastring contains a range, the `content` will be returned as-is - * without any parsing. The returned `lineClassNames` will be a map from that - * number range to the first magic comment config entry (which _should_ be for - * line highlight directives.) - * - * @param content The raw code with magic comments. Trailing newline will be - * trimmed upfront. - * @param options Options for parsing behavior. - */ -export function parseLines( - content: string, - options: { - /** - * The full metastring, as received from MDX. Line ranges declared here - * start at 1. - */ - metastring: string | undefined; - /** - * Language of the code block, used to determine which kinds of magic - * comment styles to enable. - */ - language: string | undefined; - /** - * Magic comment types that we should try to parse. Each entry would - * correspond to one class name to apply to each line. - */ - magicComments: MagicCommentConfig[]; - }, -): { +type ParseCodeLinesParam = { /** - * The highlighted lines, 0-indexed. e.g. `{ 0: ["highlight", "sample"] }` - * means the 1st line should have `highlight` and `sample` as class names. + * The full metastring, as received from MDX. Line ranges declared here + * start at 1. */ - lineClassNames: {[lineIndex: number]: string[]}; + metastring: string | undefined; + /** + * Language of the code block, used to determine which kinds of magic + * comment styles to enable. + */ + language: string | undefined; + /** + * Magic comment types that we should try to parse. Each entry would + * correspond to one class name to apply to each line. + */ + magicComments: MagicCommentConfig[]; +}; + +/** + * Code lines after applying magic comments or metastring highlight ranges + */ +type CodeLines = { /** * If there's number range declared in the metastring, the code block is * returned as-is (no parsing); otherwise, this is the clean code with all * magic comments stripped away. */ code: string; -} { - let code = content.replace(/\r?\n$/, ''); - const {language, magicComments, metastring} = options; + /** + * The highlighted lines, 0-indexed. e.g. `{ 0: ["highlight", "sample"] }` + * means the 1st line should have `highlight` and `sample` as class names. + */ + lineClassNames: {[lineIndex: number]: string[]}; +}; + +function parseCodeLinesFromMetastring( + code: string, + {metastring, magicComments}: ParseCodeLinesParam, +): CodeLines | null { // Highlighted lines specified in props: don't parse the content if (metastring && metastringLinesRangeRegex.test(metastring)) { const linesRange = metastring.match(metastringLinesRangeRegex)!.groups! @@ -258,6 +250,14 @@ export function parseLines( .map((n) => [n - 1, [metastringRangeClassName]] as [number, string[]]); return {lineClassNames: Object.fromEntries(lines), code}; } + return null; +} + +function parseCodeLinesFromContent( + code: string, + params: ParseCodeLinesParam, +): CodeLines { + const {language, magicComments} = params; if (language === undefined) { return {lineClassNames: {}, code}; } @@ -307,7 +307,7 @@ export function parseLines( } lines.splice(lineNumber, 1); } - code = lines.join('\n'); + const lineClassNames: {[lineIndex: number]: string[]} = {}; Object.entries(blocks).forEach(([className, {range}]) => { rangeParser(range).forEach((l) => { @@ -315,7 +315,31 @@ export function parseLines( lineClassNames[l]!.push(className); }); }); - return {lineClassNames, code}; + + return {code: lines.join('\n'), lineClassNames}; +} + +/** + * Parses the code content, strips away any magic comments, and returns the + * clean content and the highlighted lines marked by the comments or metastring. + * + * If the metastring contains a range, the `content` will be returned as-is + * without any parsing. The returned `lineClassNames` will be a map from that + * number range to the first magic comment config entry (which _should_ be for + * line highlight directives.) + */ +export function parseLines( + code: string, + params: ParseCodeLinesParam, +): CodeLines { + // Historical behavior: we remove last line break + const newCode = code.replace(/\r?\n$/, ''); + // Historical behavior: we try one strategy after the other + // we don't support mixing metastring ranges + magic comments + return ( + parseCodeLinesFromMetastring(newCode, {...params}) ?? + parseCodeLinesFromContent(newCode, {...params}) + ); } export function getPrismCssVariables(prismTheme: PrismTheme): CSSProperties { diff --git a/project-words.txt b/project-words.txt index 73c418bb1f..dda7cd76d6 100644 --- a/project-words.txt +++ b/project-words.txt @@ -175,6 +175,7 @@ Meilisearch merveilleuse metadatum metastring +Metastring metrica Metrika microdata