diff --git a/packages/cli/tests/config/loadUserConfig.spec.ts b/packages/cli/tests/config/loadUserConfig.spec.ts index 3327d9bd05..be905d5fb8 100644 --- a/packages/cli/tests/config/loadUserConfig.spec.ts +++ b/packages/cli/tests/config/loadUserConfig.spec.ts @@ -47,31 +47,29 @@ const MJS_CASES: [string, unknown][] = [ ], ] -describe('cli > config > loadUserConfig', () => { - describe('should load ts config file correctly', () => { - TS_CASES.forEach(([source, expected]) => { - it(JSON.stringify(source), async () => { - const { userConfig } = await loadUserConfig(source) - expect(userConfig).toEqual(expected) - }) +describe('should load ts config file correctly', () => { + TS_CASES.forEach(([source, expected]) => { + it(JSON.stringify(source), async () => { + const { userConfig } = await loadUserConfig(source) + expect(userConfig).toEqual(expected) }) }) +}) - describe('should load js config file correctly', () => { - JS_CASES.forEach(([source, expected]) => { - it(JSON.stringify(source), async () => { - const { userConfig } = await loadUserConfig(source) - expect(userConfig).toEqual(expected) - }) +describe('should load js config file correctly', () => { + JS_CASES.forEach(([source, expected]) => { + it(JSON.stringify(source), async () => { + const { userConfig } = await loadUserConfig(source) + expect(userConfig).toEqual(expected) }) }) +}) - describe('should load mjs config file correctly', () => { - MJS_CASES.forEach(([source, expected]) => { - it(JSON.stringify(source), async () => { - const { userConfig } = await loadUserConfig(source) - expect(userConfig).toEqual(expected) - }) +describe('should load mjs config file correctly', () => { + MJS_CASES.forEach(([source, expected]) => { + it(JSON.stringify(source), async () => { + const { userConfig } = await loadUserConfig(source) + expect(userConfig).toEqual(expected) }) }) }) diff --git a/packages/cli/tests/config/resolveUserConfigConventionalPath.spec.ts b/packages/cli/tests/config/resolveUserConfigConventionalPath.spec.ts index 808ac4ec19..4cd31fe353 100644 --- a/packages/cli/tests/config/resolveUserConfigConventionalPath.spec.ts +++ b/packages/cli/tests/config/resolveUserConfigConventionalPath.spec.ts @@ -14,13 +14,11 @@ const TEST_CASES: [string, string][] = [ [resolveFixtures('case6'), '.vuepress/config.mjs'], ] -describe('cli > config > resolveUserConfigConventionalPath', () => { - describe('should resolve conventional config file correctly', () => { - TEST_CASES.forEach(([source, expected]) => { - it(expected, () => { - const configFile = resolveUserConfigConventionalPath(source, source) - expect(configFile).toEqual(path.resolve(source, expected)) - }) +describe('should resolve conventional config file correctly', () => { + TEST_CASES.forEach(([source, expected]) => { + it(expected, () => { + const configFile = resolveUserConfigConventionalPath(source, source) + expect(configFile).toEqual(path.resolve(source, expected)) }) }) }) diff --git a/packages/cli/tests/config/resolveUserConfigPath.spec.ts b/packages/cli/tests/config/resolveUserConfigPath.spec.ts index 4fdc25f309..6daa4b490c 100644 --- a/packages/cli/tests/config/resolveUserConfigPath.spec.ts +++ b/packages/cli/tests/config/resolveUserConfigPath.spec.ts @@ -1,32 +1,30 @@ import { path } from '@vuepress/utils' -import { describe, expect, it, vi } from 'vitest' +import { expect, it, vi } from 'vitest' import { resolveUserConfigPath } from '../../src/index.js' const resolveFixtures = (str: string): string => path.resolve(__dirname, '../__fixtures__/config', str) -describe('cli > config > resolveUserConfigPath', () => { - it('should resolve absolute file path correctly', () => { - const absolutePath = resolveFixtures('custom-config.ts') - const configFile = resolveUserConfigPath(absolutePath) - expect(configFile).toEqual(absolutePath) - }) +it('should resolve absolute file path correctly', () => { + const absolutePath = resolveFixtures('custom-config.ts') + const configFile = resolveUserConfigPath(absolutePath) + expect(configFile).toEqual(absolutePath) +}) - it('should resolve relative file path correctly', () => { - const relativePath = 'custom-config.ts' - const configFile = resolveUserConfigPath(relativePath, resolveFixtures('')) - expect(configFile).toEqual(resolveFixtures(relativePath)) - }) +it('should resolve relative file path correctly', () => { + const relativePath = 'custom-config.ts' + const configFile = resolveUserConfigPath(relativePath, resolveFixtures('')) + expect(configFile).toEqual(resolveFixtures(relativePath)) +}) - it('should throw an error if file does not exist', () => { - const consoleError = console.error - console.error = vi.fn() +it('should throw an error if file does not exist', () => { + const consoleError = console.error + console.error = vi.fn() - expect(() => { - resolveUserConfigPath('4-0-4') - }).toThrow() - expect(console.error).toHaveBeenCalled() + expect(() => { + resolveUserConfigPath('4-0-4') + }).toThrow() + expect(console.error).toHaveBeenCalled() - console.error = consoleError - }) + console.error = consoleError }) diff --git a/packages/core/tests/app/resolveAppEnv.spec.ts b/packages/core/tests/app/resolveAppEnv.spec.ts index 8f0a8e2010..3c2ad10b83 100644 --- a/packages/core/tests/app/resolveAppEnv.spec.ts +++ b/packages/core/tests/app/resolveAppEnv.spec.ts @@ -1,48 +1,39 @@ -import { describe, expect, it } from 'vitest' +import { expect, it } from 'vitest' import type { Bundler } from '../../src/index.js' import { resolveAppEnv, resolveAppOptions } from '../../src/index.js' -const TEST_CASES: [ - Parameters, - ReturnType, -][] = [ - [ - [ - resolveAppOptions({ - source: '/foo', - theme: { name: 'test' }, - bundler: {} as Bundler, - }), - ], - { +const TEST_CASES = [ + { + name: 'should resolve app env correctly without debug flag', + options: resolveAppOptions({ + source: '/foo', + theme: { name: 'test' }, + bundler: {} as Bundler, + }), + expected: { isBuild: false, isDev: false, isDebug: false, }, - ], - [ - [ - resolveAppOptions({ - source: '/foo', - theme: { name: 'test' }, - bundler: {} as Bundler, - debug: true, - }), - ], - { + }, + { + name: 'should resolve app env correctly with debug flag', + options: resolveAppOptions({ + source: '/foo', + theme: { name: 'test' }, + bundler: {} as Bundler, + debug: true, + }), + expected: { isBuild: false, isDev: false, isDebug: true, }, - ], + }, ] -describe('core > app > resolveAppEnv', () => { - describe('should create app env correctly', () => { - TEST_CASES.forEach(([params, expected], i) => { - it(`case ${i}`, () => { - expect(resolveAppEnv(...params)).toEqual(expected) - }) - }) +TEST_CASES.forEach(({ name, options, expected }) => { + it(name, () => { + expect(resolveAppEnv(options)).toEqual(expected) }) }) diff --git a/packages/core/tests/app/resolveAppOptions.spec.ts b/packages/core/tests/app/resolveAppOptions.spec.ts index 442737587d..29b2d07d2d 100644 --- a/packages/core/tests/app/resolveAppOptions.spec.ts +++ b/packages/core/tests/app/resolveAppOptions.spec.ts @@ -1,49 +1,47 @@ import { path, templateRenderer } from '@vuepress/utils' -import { describe, expect, it } from 'vitest' +import { expect, it } from 'vitest' import type { Bundler } from '../../src/index.js' import { resolveAppOptions } from '../../src/index.js' -describe('core > app > resolveAppOptions', () => { - it('should create app options with default values', () => { - const source = '/foo' +it('should create app options with default values', () => { + const source = '/foo' - expect( - resolveAppOptions({ - source, - theme: { name: 'theme' }, - bundler: { name: 'bundler' } as Bundler, - }), - ).toEqual({ - base: '/', - lang: 'en-US', - title: '', - description: '', - head: [], - locales: {}, - theme: { name: 'theme' }, - bundler: { name: 'bundler' }, + expect( + resolveAppOptions({ source, - dest: path.resolve(source, '.vuepress/dist'), - temp: path.resolve(source, '.vuepress/.temp'), - cache: path.resolve(source, '.vuepress/.cache'), - public: path.resolve(source, '.vuepress/public'), - debug: false, - host: '0.0.0.0', - port: 8080, - open: false, - pagePatterns: ['**/*.md', '!.vuepress', '!node_modules'], - permalinkPattern: null, - templateDev: path.normalize( - require.resolve('@vuepress/client/templates/dev.html'), - ), - templateBuild: path.normalize( - require.resolve('@vuepress/client/templates/build.html'), - ), - templateBuildRenderer: templateRenderer, - shouldPreload: true, - shouldPrefetch: true, - markdown: {}, - plugins: [], - }) + theme: { name: 'theme' }, + bundler: { name: 'bundler' } as Bundler, + }), + ).toEqual({ + base: '/', + lang: 'en-US', + title: '', + description: '', + head: [], + locales: {}, + theme: { name: 'theme' }, + bundler: { name: 'bundler' }, + source, + dest: path.resolve(source, '.vuepress/dist'), + temp: path.resolve(source, '.vuepress/.temp'), + cache: path.resolve(source, '.vuepress/.cache'), + public: path.resolve(source, '.vuepress/public'), + debug: false, + host: '0.0.0.0', + port: 8080, + open: false, + pagePatterns: ['**/*.md', '!.vuepress', '!node_modules'], + permalinkPattern: null, + templateDev: path.normalize( + require.resolve('@vuepress/client/templates/dev.html'), + ), + templateBuild: path.normalize( + require.resolve('@vuepress/client/templates/build.html'), + ), + templateBuildRenderer: templateRenderer, + shouldPreload: true, + shouldPrefetch: true, + markdown: {}, + plugins: [], }) }) diff --git a/packages/core/tests/app/resolveAppPages.spec.ts b/packages/core/tests/app/resolveAppPages.spec.ts index f394888238..73abc40368 100644 --- a/packages/core/tests/app/resolveAppPages.spec.ts +++ b/packages/core/tests/app/resolveAppPages.spec.ts @@ -1,93 +1,91 @@ import { createMarkdown } from '@vuepress/markdown' import { path } from '@vuepress/utils' -import { describe, expect, it } from 'vitest' +import { expect, it } from 'vitest' import type { Bundler } from '../../src/index.js' import { createBaseApp, resolveAppPages } from '../../src/index.js' -describe('core > app > resolveAppPages', () => { - it('should create two pages with default 404 page', async () => { - const app = createBaseApp({ - source: path.resolve(__dirname, '../__fixtures__/pages'), - theme: { name: 'test' }, - bundler: {} as Bundler, - }) - app.markdown = createMarkdown() +it('should create two pages with default 404 page', async () => { + const app = createBaseApp({ + source: path.resolve(__dirname, '../__fixtures__/pages'), + theme: { name: 'test' }, + bundler: {} as Bundler, + }) + app.markdown = createMarkdown() + + const pages = await resolveAppPages(app) + const fooPage = pages.find((page) => page.path === '/foo.html') + const barPage = pages.find((page) => page.path === '/bar.html') + const notFoundPage = pages.find((page) => page.path === '/404.html') - const pages = await resolveAppPages(app) - const fooPage = pages.find((page) => page.path === '/foo.html') - const barPage = pages.find((page) => page.path === '/bar.html') - const notFoundPage = pages.find((page) => page.path === '/404.html') + expect(pages).toHaveLength(3) + expect(fooPage?.filePathRelative).toEqual('foo.md') + expect(barPage?.filePathRelative).toEqual('bar.md') + expect(notFoundPage?.filePathRelative).toBeNull() + expect(notFoundPage?.frontmatter.layout).toEqual('NotFound') +}) - expect(pages).toHaveLength(3) - expect(fooPage?.filePathRelative).toEqual('foo.md') - expect(barPage?.filePathRelative).toEqual('bar.md') - expect(notFoundPage?.filePathRelative).toBeNull() - expect(notFoundPage?.frontmatter.layout).toEqual('NotFound') +it('should create two pages with custom 404 page', async () => { + const app = createBaseApp({ + source: path.resolve(__dirname, '../__fixtures__/pages-with-404'), + theme: { name: 'test' }, + bundler: {} as Bundler, }) + app.markdown = createMarkdown() - it('should create two pages with custom 404 page', async () => { - const app = createBaseApp({ - source: path.resolve(__dirname, '../__fixtures__/pages-with-404'), - theme: { name: 'test' }, - bundler: {} as Bundler, - }) - app.markdown = createMarkdown() + const pages = await resolveAppPages(app) + const fooPage = pages.find((page) => page.path === '/foo.html') + const barPage = pages.find((page) => page.path === '/bar.html') + const notFoundPage = pages.find((page) => page.path === '/404.html') - const pages = await resolveAppPages(app) - const fooPage = pages.find((page) => page.path === '/foo.html') - const barPage = pages.find((page) => page.path === '/bar.html') - const notFoundPage = pages.find((page) => page.path === '/404.html') + expect(pages).toHaveLength(3) + expect(fooPage?.filePathRelative).toEqual('foo.md') + expect(barPage?.filePathRelative).toEqual('bar.md') + expect(notFoundPage?.filePathRelative).toEqual('404.md') +}) - expect(pages).toHaveLength(3) - expect(fooPage?.filePathRelative).toEqual('foo.md') - expect(barPage?.filePathRelative).toEqual('bar.md') - expect(notFoundPage?.filePathRelative).toEqual('404.md') +it('should process extendsPageOptions hook correctly', async () => { + const app = createBaseApp({ + source: path.resolve(__dirname, '../__fixtures__/pages-with-404'), + theme: { name: 'test' }, + bundler: {} as Bundler, }) - it('should process extendsPageOptions hook correctly', async () => { - const app = createBaseApp({ - source: path.resolve(__dirname, '../__fixtures__/pages-with-404'), - theme: { name: 'test' }, - bundler: {} as Bundler, - }) - - app.use({ - name: 'foo', - extendsPageOptions: (pageOptions) => { - if (!pageOptions.frontmatter) pageOptions.frontmatter = {} - pageOptions.frontmatter.foo = 'bar' - }, - }) - app.pluginApi.registerHooks() - app.markdown = createMarkdown() + app.use({ + name: 'foo', + extendsPageOptions: (pageOptions) => { + if (!pageOptions.frontmatter) pageOptions.frontmatter = {} + pageOptions.frontmatter.foo = 'bar' + }, + }) + app.pluginApi.registerHooks() + app.markdown = createMarkdown() - const pages = await resolveAppPages(app) + const pages = await resolveAppPages(app) - pages.forEach((page) => { - expect(page.frontmatter.foo).toBe('bar') - }) + pages.forEach((page) => { + expect(page.frontmatter.foo).toBe('bar') }) +}) - it('should process extendsPage hook correctly', async () => { - const app = createBaseApp({ - source: path.resolve(__dirname, '../__fixtures__/pages-with-404'), - theme: { name: 'test' }, - bundler: {} as Bundler, - }) +it('should process extendsPage hook correctly', async () => { + const app = createBaseApp({ + source: path.resolve(__dirname, '../__fixtures__/pages-with-404'), + theme: { name: 'test' }, + bundler: {} as Bundler, + }) - app.use({ - name: 'foo', - extendsPage: (page) => { - page.frontmatter.foo = 'baz' - }, - }) - app.pluginApi.registerHooks() - app.markdown = createMarkdown() + app.use({ + name: 'foo', + extendsPage: (page) => { + page.frontmatter.foo = 'baz' + }, + }) + app.pluginApi.registerHooks() + app.markdown = createMarkdown() - const pages = await resolveAppPages(app) + const pages = await resolveAppPages(app) - pages.forEach((page) => { - expect(page.frontmatter.foo).toBe('baz') - }) + pages.forEach((page) => { + expect(page.frontmatter.foo).toBe('baz') }) }) diff --git a/packages/core/tests/app/resolvePluginObject.spec.ts b/packages/core/tests/app/resolvePluginObject.spec.ts index d359120252..a9daeb0e67 100644 --- a/packages/core/tests/app/resolvePluginObject.spec.ts +++ b/packages/core/tests/app/resolvePluginObject.spec.ts @@ -1,5 +1,5 @@ import { path } from '@vuepress/utils' -import { describe, expect, it, vi } from 'vitest' +import { expect, it, vi } from 'vitest' import type { Bundler, PluginFunction, PluginObject } from '../../src/index.js' import { createBaseApp, resolvePluginObject } from '../../src/index.js' @@ -9,25 +9,23 @@ const app = createBaseApp({ bundler: {} as Bundler, }) -describe('core > app > resolvePluginObject', () => { - it('should work with plugin object', () => { - const pluginObject: PluginObject = { - name: 'plugin-object', - } +it('should work with plugin object', () => { + const pluginObject: PluginObject = { + name: 'plugin-object', + } - const result = resolvePluginObject(app, pluginObject) - expect(result.name).toEqual('plugin-object') - }) + const result = resolvePluginObject(app, pluginObject) + expect(result.name).toEqual('plugin-object') +}) - it('should work with plugin function', () => { - const pluginFunction: PluginFunction = vi.fn(() => ({ - name: 'plugin-function', - })) +it('should work with plugin function', () => { + const pluginFunction: PluginFunction = vi.fn(() => ({ + name: 'plugin-function', + })) - const result = resolvePluginObject(app, pluginFunction) + const result = resolvePluginObject(app, pluginFunction) - expect(pluginFunction).toHaveBeenCalledTimes(1) - expect(pluginFunction).toHaveBeenCalledWith(app) - expect(result.name).toEqual('plugin-function') - }) + expect(pluginFunction).toHaveBeenCalledTimes(1) + expect(pluginFunction).toHaveBeenCalledWith(app) + expect(result.name).toEqual('plugin-function') }) diff --git a/packages/core/tests/app/resolveThemeInfo.spec.ts b/packages/core/tests/app/resolveThemeInfo.spec.ts index 631deb2e6a..453bae2c90 100644 --- a/packages/core/tests/app/resolveThemeInfo.spec.ts +++ b/packages/core/tests/app/resolveThemeInfo.spec.ts @@ -23,76 +23,74 @@ const getThemePlugin = async ( return typeof theme === 'function' ? theme(app) : theme } -describe('core > app > resolveThemeInfo', () => { - describe('plugins', () => { - describe('should resolve theme info without plugins correctly', () => { - THEME_ENTRY_TYPES.forEach((item) => { - it(item, async () => { - const themePath = fixtures(`themes/${item}-empty.js`) - const app = await createTestApp(themePath) - expect(resolveThemeInfo(app, app.options.theme).plugins).toEqual([ - await getThemePlugin(themePath, app), - ]) - }) +describe('plugins', () => { + describe('should resolve theme info without plugins correctly', () => { + THEME_ENTRY_TYPES.forEach((item) => { + it(item, async () => { + const themePath = fixtures(`themes/${item}-empty.js`) + const app = await createTestApp(themePath) + expect(resolveThemeInfo(app, app.options.theme).plugins).toEqual([ + await getThemePlugin(themePath, app), + ]) }) }) + }) - describe('should resolve theme info with plugins correctly', () => { - THEME_ENTRY_TYPES.forEach((item) => { - it(item, async () => { - const themePath = fixtures(`themes/${item}.js`) - const app = await createTestApp(themePath) - expect(resolveThemeInfo(app, app.options.theme).plugins).toEqual([ - await importFileDefault(fixtures('plugins/obj.js')), - await getThemePlugin(themePath, app), - ]) - }) + describe('should resolve theme info with plugins correctly', () => { + THEME_ENTRY_TYPES.forEach((item) => { + it(item, async () => { + const themePath = fixtures(`themes/${item}.js`) + const app = await createTestApp(themePath) + expect(resolveThemeInfo(app, app.options.theme).plugins).toEqual([ + await importFileDefault(fixtures('plugins/obj.js')), + await getThemePlugin(themePath, app), + ]) }) }) }) +}) - describe('extends', () => { - describe('should resolve theme info with parent theme correctly', () => { - THEME_ENTRY_TYPES.forEach((item) => { - it(item, async () => { - const themePath = fixtures(`themes/${item}-extends-parent.js`) - const parentThemePath = fixtures(`themes/${item}.js`) - const app = await createTestApp(themePath) +describe('extends', () => { + describe('should resolve theme info with parent theme correctly', () => { + THEME_ENTRY_TYPES.forEach((item) => { + it(item, async () => { + const themePath = fixtures(`themes/${item}-extends-parent.js`) + const parentThemePath = fixtures(`themes/${item}.js`) + const app = await createTestApp(themePath) - expect(resolveThemeInfo(app, app.options.theme)).toEqual({ - plugins: [ - await importFileDefault(fixtures('plugins/obj.js')), - await getThemePlugin(parentThemePath, app), - await importFileDefault(fixtures('plugins/obj-foo.js')), - await getThemePlugin(themePath, app), - ], - templateBuild: `theme-${item}-extends-parent-template-build`, - templateDev: `theme-${item}-template-dev`, - }) + expect(resolveThemeInfo(app, app.options.theme)).toEqual({ + plugins: [ + await importFileDefault(fixtures('plugins/obj.js')), + await getThemePlugin(parentThemePath, app), + await importFileDefault(fixtures('plugins/obj-foo.js')), + await getThemePlugin(themePath, app), + ], + templateBuild: `theme-${item}-extends-parent-template-build`, + templateDev: `theme-${item}-template-dev`, }) }) }) + }) - describe('should resolve theme info with grandparent theme correctly', () => { - THEME_ENTRY_TYPES.forEach((item) => { - it(item, async () => { - const themePath = fixtures(`themes/${item}-extends-grandparent.js`) - const parentThemePath = fixtures(`themes/${item}-extends-parent.js`) - const grandparentThemePath = fixtures(`themes/${item}.js`) - const app = await createTestApp(themePath) + describe('should resolve theme info with grandparent theme correctly', () => { + THEME_ENTRY_TYPES.forEach((item) => { + it(item, async () => { + const themePath = fixtures(`themes/${item}-extends-grandparent.js`) + const parentThemePath = fixtures(`themes/${item}-extends-parent.js`) + const grandparentThemePath = fixtures(`themes/${item}.js`) + const app = await createTestApp(themePath) - expect(resolveThemeInfo(app, app.options.theme)).toEqual({ - plugins: [ - await importFileDefault(fixtures('plugins/obj.js')), - await getThemePlugin(grandparentThemePath, app), - await importFileDefault(fixtures('plugins/obj-foo.js')), - await getThemePlugin(parentThemePath, app), - await importFileDefault(fixtures('plugins/obj-bar.js')), - await getThemePlugin(themePath, app), - ], - templateBuild: `theme-${item}-extends-parent-template-build`, - templateDev: `theme-${item}-extends-grandparent-template-dev`, - }) + expect(resolveThemeInfo(app, app.options.theme)).toEqual({ + plugins: [ + await importFileDefault(fixtures('plugins/obj.js')), + await getThemePlugin(grandparentThemePath, app), + await importFileDefault(fixtures('plugins/obj-foo.js')), + await getThemePlugin(parentThemePath, app), + await importFileDefault(fixtures('plugins/obj-bar.js')), + await getThemePlugin(themePath, app), + ], + templateBuild: `theme-${item}-extends-parent-template-build`, + templateDev: `theme-${item}-extends-grandparent-template-dev`, }) }) }) diff --git a/packages/markdown/tests/markdown.spec.ts b/packages/markdown/tests/markdown.spec.ts index ec5ddfffbe..0cf9097b44 100644 --- a/packages/markdown/tests/markdown.spec.ts +++ b/packages/markdown/tests/markdown.spec.ts @@ -1,26 +1,24 @@ -import { describe, expect, it } from 'vitest' +import { expect, it } from 'vitest' import { createMarkdown } from '../src/index.js' -describe('@vuepress/markdown > markdown', () => { - const md = createMarkdown() +const md = createMarkdown() - it('should render anchors', () => { - const rendered = md.render(`\ +it('should render anchors', () => { + const rendered = md.render(`\ # h1 ## h2 ### h3 `) - expect(rendered).toEqual( - [ - '

h1

', - '

h2

', - '

h3

', - ].join('\n') + '\n', - ) - }) + expect(rendered).toEqual( + [ + '

h1

', + '

h2

', + '

h3

', + ].join('\n') + '\n', + ) +}) - it('should parse emoji', () => { - const rendered = md.render(':smile:') - expect(rendered).toBe('

😄

\n') - }) +it('should parse emoji', () => { + const rendered = md.render(':smile:') + expect(rendered).toBe('

😄

\n') }) diff --git a/packages/markdown/tests/plugins/__snapshots__/importCodePlugin.spec.ts.snap b/packages/markdown/tests/plugins/__snapshots__/importCodePlugin.spec.ts.snap index afce065776..315d75627c 100644 --- a/packages/markdown/tests/plugins/__snapshots__/importCodePlugin.spec.ts.snap +++ b/packages/markdown/tests/plugins/__snapshots__/importCodePlugin.spec.ts.snap @@ -1,6 +1,6 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`@vuepress/markdown > plugins > importCodePlugin > compatibility with otherPlugin > should preserve the things after code as fence info 1`] = ` +exports[`compatibility with otherPlugin > should preserve the things after code as fence info 1`] = ` "
const msg = 'hello from js'
 
 console.log(msg)
@@ -10,7 +10,7 @@ console.log('foo bar')
 "
 `;
 
-exports[`@vuepress/markdown > plugins > importCodePlugin > compatibility with otherPlugin > should preserve the things after code as fence info 2`] = `
+exports[`compatibility with otherPlugin > should preserve the things after code as fence info 2`] = `
 "
# msg
 
 hello from md
diff --git a/packages/markdown/tests/plugins/__snapshots__/vPrePlugin.spec.ts.snap b/packages/markdown/tests/plugins/__snapshots__/vPrePlugin.spec.ts.snap
index 6cb750f95f..a06960e9b8 100644
--- a/packages/markdown/tests/plugins/__snapshots__/vPrePlugin.spec.ts.snap
+++ b/packages/markdown/tests/plugins/__snapshots__/vPrePlugin.spec.ts.snap
@@ -1,6 +1,6 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`@vuepress/markdown > plugins > vPrePlugin > :v-pre / :no-v-pre > should work if \`block\` is disabled 1`] = `
+exports[`:v-pre / :no-v-pre > should work if \`block\` is disabled 1`] = `
 "
const a = 1
 
const a = 1
@@ -18,7 +18,7 @@ exports[`@vuepress/markdown > plugins > vPrePlugin > :v-pre / :no-v-pre > should
 "
 `;
 
-exports[`@vuepress/markdown > plugins > vPrePlugin > :v-pre / :no-v-pre > should work if \`block\` is enabled by default 1`] = `
+exports[`:v-pre / :no-v-pre > should work if \`block\` is enabled by default 1`] = `
 "
const a = 1
 
const a = 1
@@ -36,35 +36,35 @@ exports[`@vuepress/markdown > plugins > vPrePlugin > :v-pre / :no-v-pre > should
 "
 `;
 
-exports[`@vuepress/markdown > plugins > vPrePlugin > plugin options > should disable \`block\` 1`] = `
+exports[`plugin options > should disable \`block\` 1`] = `
 "
const a = 1
 

inline

" `; -exports[`@vuepress/markdown > plugins > vPrePlugin > plugin options > should disable \`block\` and \`inline\` 1`] = ` +exports[`plugin options > should disable \`block\` and \`inline\` 1`] = ` "
const a = 1
 

inline

" `; -exports[`@vuepress/markdown > plugins > vPrePlugin > plugin options > should disable \`inline\` 1`] = ` +exports[`plugin options > should disable \`inline\` 1`] = ` "
const a = 1
 

inline

" `; -exports[`@vuepress/markdown > plugins > vPrePlugin > plugin options > should process code with default options 1`] = ` +exports[`plugin options > should process code with default options 1`] = ` "
const a = 1
 

inline

" `; -exports[`@vuepress/markdown > plugins > vPrePlugin > syntax highlighting > should work highlighted code is wrapped with \`
\` 1`] = `
+exports[`syntax highlighting > should work highlighted code is wrapped with \`
\` 1`] = `
 "
highlighted code: const a = 1
 , lang: js:v-pre
highlighted code: const a = 1
@@ -82,7 +82,7 @@ exports[`@vuepress/markdown > plugins > vPrePlugin > syntax highlighting > shoul
 "
 `;
 
-exports[`@vuepress/markdown > plugins > vPrePlugin > syntax highlighting > should work if highlighted code is not wrapped with \`
\` 1`] = `
+exports[`syntax highlighting > should work if highlighted code is not wrapped with \`
\` 1`] = `
 "
highlighted code: const a = 1
 , lang: js:v-pre
highlighted code: const a = 1
diff --git a/packages/markdown/tests/plugins/assetsPlugin.spec.ts b/packages/markdown/tests/plugins/assetsPlugin.spec.ts
index af149f84d9..c209ce0731 100644
--- a/packages/markdown/tests/plugins/assetsPlugin.spec.ts
+++ b/packages/markdown/tests/plugins/assetsPlugin.spec.ts
@@ -3,39 +3,292 @@ import { describe, expect, it } from 'vitest'
 import type { MarkdownEnv } from '../../src/index.js'
 import { assetsPlugin } from '../../src/index.js'
 
-describe('@vuepress/markdown > plugins > assetsPlugin', () => {
-  describe('markdown image syntax', () => {
+describe('markdown image syntax', () => {
+  const source = [
+    // relative paths
+    '![foo](./foo.png)',
+    '![foo2](../sub/foo.png)',
+    '![foo-bar](./foo/bar.png)',
+    '![foo-bar2](../sub/foo/bar.png)',
+    '![baz](../baz.png)',
+    '![out](../../out.png)',
+    '![汉字](./汉字.png)',
+    '![100%](./100%.png)',
+    // absolute paths
+    '![absolute](/absolute.png)',
+    '![absolute-foo](/foo/absolute.png)',
+    // no-prefix paths
+    '![no-prefix](no-prefix.png)',
+    '![no-prefix-foo](foo/no-prefix.png)',
+    '![alias](@alias/foo.png)',
+    '![汉字](@alias/汉字.png)',
+    '![100%](@alias/100%.png)',
+    '![~alias](~@alias/foo.png)',
+    '![~汉字](~@alias/汉字.png)',
+    '![~100%](~@alias/100%.png)',
+    // keep as is
+    '![url](http://foobar.com/icon.png)',
+    '![empty]()',
+    // invalid paths
+    '![invalid](.../invalid.png)',
+    '![汉字](.../汉字.png)',
+    '![100%](.../100%.png)',
+    // data uri
+    '![data-uri](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wr4H/wAAAABJRU5ErkJggg==)',
+  ]
+
+  const TEST_CASES: {
+    description: string
+    md: MarkdownIt
+    env: MarkdownEnv
+    expected: string[]
+  }[] = [
+    {
+      description: 'should handle assets link with default options',
+      md: MarkdownIt().use(assetsPlugin),
+      env: {
+        base: '/base/',
+        filePathRelative: 'sub/foo.md',
+      },
+      expected: [
+        // relative paths
+        'foo',
+        'foo2',
+        'foo-bar',
+        'foo-bar2',
+        'baz',
+        'out',
+        '汉字',
+        '100%',
+        // absolute paths
+        'absolute',
+        'absolute-foo',
+        // no-prefix paths
+        'no-prefix',
+        'no-prefix-foo',
+        'alias',
+        '汉字',
+        '100%',
+        '~alias',
+        '~汉字',
+        '~100%',
+        // keep as is
+        'url',
+        'empty',
+        // invalid paths
+        'invalid',
+        '汉字',
+        '100%',
+        // data uri
+        'data-uri',
+      ],
+    },
+    {
+      description: 'should respect `absolutePathPrependBase` option',
+      md: MarkdownIt().use(assetsPlugin, {
+        absolutePathPrependBase: true,
+      }),
+      env: {
+        base: '/base/',
+        filePathRelative: 'sub/foo.md',
+      },
+      expected: [
+        // relative paths
+        'foo',
+        'foo2',
+        'foo-bar',
+        'foo-bar2',
+        'baz',
+        'out',
+        '汉字',
+        '100%',
+        // absolute paths
+        'absolute',
+        'absolute-foo',
+        // no-prefix paths
+        'no-prefix',
+        'no-prefix-foo',
+        'alias',
+        '汉字',
+        '100%',
+        '~alias',
+        '~汉字',
+        '~100%',
+        // keep as is
+        'url',
+        'empty',
+        // invalid paths
+        'invalid',
+        '汉字',
+        '100%',
+        // data uri
+        'data-uri',
+      ],
+    },
+    {
+      description: 'should respect `relativePathPrefix` option',
+      md: MarkdownIt().use(assetsPlugin, {
+        relativePathPrefix: '@foo',
+      }),
+      env: {
+        filePathRelative: 'sub/foo.md',
+      },
+      expected: [
+        // relative paths
+        'foo',
+        'foo2',
+        'foo-bar',
+        'foo-bar2',
+        'baz',
+        'out',
+        '汉字',
+        '100%',
+        // absolute paths
+        'absolute',
+        'absolute-foo',
+        // no-prefix paths
+        'no-prefix',
+        'no-prefix-foo',
+        'alias',
+        '汉字',
+        '100%',
+        '~alias',
+        '~汉字',
+        '~100%',
+        // keep as is
+        'url',
+        'empty',
+        // invalid paths
+        'invalid',
+        '汉字',
+        '100%',
+        // data uri
+        'data-uri',
+      ],
+    },
+    {
+      description:
+        'should not handle relative paths if `env.filePathRelative` is not provided',
+      md: MarkdownIt().use(assetsPlugin),
+      env: {},
+      expected: [
+        // relative paths
+        'foo',
+        'foo2',
+        'foo-bar',
+        'foo-bar2',
+        'baz',
+        'out',
+        '汉字',
+        '100%',
+        // absolute paths
+        'absolute',
+        'absolute-foo',
+        // no-prefix paths
+        'no-prefix',
+        'no-prefix-foo',
+        'alias',
+        '汉字',
+        '100%',
+        '~alias',
+        '~汉字',
+        '~100%',
+        // keep as is
+        'url',
+        'empty',
+        // invalid paths
+        'invalid',
+        '汉字',
+        '100%',
+        // data uri
+        'data-uri',
+      ],
+    },
+  ]
+
+  TEST_CASES.forEach(({ description, md, env, expected }) => {
+    it(description, () => {
+      expect(md.render(source.join('\n\n'), env)).toEqual(
+        `${expected.map((item) => `

${item}

`).join('\n')}\n`, + ) + }) + }) +}) + +describe('html tag', () => { + describe('single-line', () => { const source = [ + /* src */ // relative paths - '![foo](./foo.png)', - '![foo2](../sub/foo.png)', - '![foo-bar](./foo/bar.png)', - '![foo-bar2](../sub/foo/bar.png)', - '![baz](../baz.png)', - '![out](../../out.png)', - '![汉字](./汉字.png)', - '![100%](./100%.png)', + '', + '', + '', + '', + '', + '', + '', + '', + 'attrs', + // aliases + '', + '', + '', + 'attrs', + // webpack legacy aliases + '', + '', + '', + 'attrs', // absolute paths - '![absolute](/absolute.png)', - '![absolute-foo](/foo/absolute.png)', + '', + '', // no-prefix paths - '![no-prefix](no-prefix.png)', - '![no-prefix-foo](foo/no-prefix.png)', - '![alias](@alias/foo.png)', - '![汉字](@alias/汉字.png)', - '![100%](@alias/100%.png)', - '![~alias](~@alias/foo.png)', - '![~汉字](~@alias/汉字.png)', - '![~100%](~@alias/100%.png)', + '', + '', + 'attrs', + // keep as is + '', + '', + // invalid paths + '', + '', + '', + 'attrs', + + /* srcset */ + // relative paths + '', + '', + 'attrs', + // aliases + '', + 'attrs', + // webpack legacy aliases + '', + 'attrs', // keep as is - '![url](http://foobar.com/icon.png)', - '![empty]()', + '', + '', + 'attrs', // invalid paths - '![invalid](.../invalid.png)', - '![汉字](.../汉字.png)', - '![100%](.../100%.png)', - // data uri - '![data-uri](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wr4H/wAAAABJRU5ErkJggg==)', + '', + 'attrs', + // invalid srcset + '', + + /* both */ + // relative paths + '', + '', + 'attrs', + // aliases + 'attrs', + 'attrs', + // keep as is + 'attrs', + + /* data uri */ + '', ] const TEST_CASES: { @@ -46,687 +299,426 @@ describe('@vuepress/markdown > plugins > assetsPlugin', () => { }[] = [ { description: 'should handle assets link with default options', - md: MarkdownIt().use(assetsPlugin), + md: MarkdownIt({ html: true }).use(assetsPlugin), env: { - base: '/base/', filePathRelative: 'sub/foo.md', }, expected: [ + /* src */ // relative paths - 'foo', - 'foo2', - 'foo-bar', - 'foo-bar2', - 'baz', - 'out', - '汉字', - '100%', + '', + '', + '', + '', + '', + '', + '', + '', + 'attrs', + // aliases + '', + '', + '', + 'attrs', + // webpack legacy aliases + '', + '', + '', + 'attrs', // absolute paths - 'absolute', - 'absolute-foo', + '', + '', // no-prefix paths - 'no-prefix', - 'no-prefix-foo', - 'alias', - '汉字', - '100%', - '~alias', - '~汉字', - '~100%', + '', + '', + 'attrs', // keep as is - 'url', - 'empty', + '', + '', // invalid paths - 'invalid', - '汉字', - '100%', - // data uri - 'data-uri', - ], - }, - { - description: 'should respect `absolutePathPrependBase` option', - md: MarkdownIt().use(assetsPlugin, { - absolutePathPrependBase: true, - }), - env: { - base: '/base/', - filePathRelative: 'sub/foo.md', - }, - expected: [ + '', + '', + '', + 'attrs', + + /* srcset */ // relative paths - 'foo', - 'foo2', - 'foo-bar', - 'foo-bar2', - 'baz', - 'out', - '汉字', - '100%', - // absolute paths - 'absolute', - 'absolute-foo', - // no-prefix paths - 'no-prefix', - 'no-prefix-foo', - 'alias', - '汉字', - '100%', - '~alias', - '~汉字', - '~100%', + '', + '', + 'attrs', + // aliases + '', + 'attrs', + // webpack legacy aliases + '', + 'attrs', // keep as is - 'url', - 'empty', + '', + '', + 'attrs', // invalid paths - 'invalid', - '汉字', - '100%', - // data uri - 'data-uri', + '', + 'attrs', + // invalid srcset + '', + + /* both */ + // relative paths + '', + '', + 'attrs', + // aliases + 'attrs', + 'attrs', + // keep as is + 'attrs', + + /* data uri */ + '', ], }, { description: 'should respect `relativePathPrefix` option', - md: MarkdownIt().use(assetsPlugin, { + md: MarkdownIt({ html: true }).use(assetsPlugin, { relativePathPrefix: '@foo', }), env: { filePathRelative: 'sub/foo.md', }, expected: [ + /* src */ // relative paths - 'foo', - 'foo2', - 'foo-bar', - 'foo-bar2', - 'baz', - 'out', - '汉字', - '100%', + '', + '', + '', + '', + '', + '', + '', + '', + 'attrs', + // aliases + '', + '', + '', + 'attrs', + // webpack legacy aliases + '', + '', + '', + 'attrs', // absolute paths - 'absolute', - 'absolute-foo', + '', + '', // no-prefix paths - 'no-prefix', - 'no-prefix-foo', - 'alias', - '汉字', - '100%', - '~alias', - '~汉字', - '~100%', + '', + '', + 'attrs', // keep as is - 'url', - 'empty', + '', + '', // invalid paths - 'invalid', - '汉字', - '100%', - // data uri - 'data-uri', + '', + '', + '', + 'attrs', + + /* srcset */ + // relative paths + '', + '', + 'attrs', + // aliases + '', + 'attrs', + // webpack legacy aliases + '', + 'attrs', + // keep as is + '', + '', + 'attrs', + // invalid paths + '', + 'attrs', + // invalid srcset + '', + + /* both */ + // relative paths + '', + '', + 'attrs', + // aliases + 'attrs', + 'attrs', + // keep as is + 'attrs', + + /* data uri */ + '', ], }, { description: 'should not handle relative paths if `env.filePathRelative` is not provided', - md: MarkdownIt().use(assetsPlugin), + md: MarkdownIt({ html: true }).use(assetsPlugin), env: {}, expected: [ + /* src */ // relative paths - 'foo', - 'foo2', - 'foo-bar', - 'foo-bar2', - 'baz', - 'out', - '汉字', - '100%', + '', + '', + '', + '', + '', + '', + '', + '', + 'attrs', + // aliases + '', + '', + '', + 'attrs', + // webpack legacy aliases + '', + '', + '', + 'attrs', // absolute paths - 'absolute', - 'absolute-foo', + '', + '', // no-prefix paths - 'no-prefix', - 'no-prefix-foo', - 'alias', - '汉字', - '100%', - '~alias', - '~汉字', - '~100%', + '', + '', + 'attrs', + // keep as is + '', + '', + // invalid paths + '', + '', + '', + 'attrs', + + /* srcset */ + // relative paths + '', + '', + 'attrs', + // aliases + '', + 'attrs', + // webpack legacy aliases + '', + 'attrs', // keep as is - 'url', - 'empty', + '', + '', + 'attrs', // invalid paths - 'invalid', - '汉字', - '100%', - // data uri - 'data-uri', + '', + 'attrs', + // invalid srcset + '', + + /* both */ + // relative paths + '', + '', + 'attrs', + // aliases + 'attrs', + 'attrs', + // keep as is + 'attrs', + + /* data uri */ + '', ], }, ] TEST_CASES.forEach(({ description, md, env, expected }) => { it(description, () => { + // block expect(md.render(source.join('\n\n'), env)).toEqual( - `${expected.map((item) => `

${item}

`).join('\n')}\n`, + expected.map((item) => item).join('\n'), ) - }) - }) - }) - describe('html tag', () => { - describe('single-line', () => { - const source = [ - /* src */ - // relative paths - '', - '', - '', - '', - '', - '', - '', - '', - 'attrs', - // aliases - '', - '', - '', - 'attrs', - // webpack legacy aliases - '', - '', - '', - 'attrs', - // absolute paths - '', - '', - // no-prefix paths - '', - '', - 'attrs', - // keep as is - '', - '', - // invalid paths - '', - '', - '', - 'attrs', + // block with leading white space + expect( + md.render(source.map((item) => ` ${item}`).join('\n\n'), env), + ).toEqual(expected.map((item) => ` ${item}`).join('\n')) + + // inline with prefix + expect( + md.render(source.map((item) => `foo${item}`).join('\n\n'), env), + ).toEqual(`${expected.map((item) => `

foo${item}

`).join('\n')}\n`) + + // inline with suffix + expect( + md.render(source.map((item) => `${item}foo`).join('\n\n'), env), + ).toEqual(`${expected.map((item) => `

${item}foo

`).join('\n')}\n`) + + // inline with line break + expect( + md.render( + source.map((item) => item.replace(' `

${item.replace('`) + .join('\n')}\n`, + ) - /* srcset */ - // relative paths - '', - '', - 'attrs', - // aliases - '', - 'attrs', - // webpack legacy aliases - '', - 'attrs', - // keep as is - '', - '', - 'attrs', - // invalid paths - '', - 'attrs', - // invalid srcset - '', + // wrapped item + expect( + md.render(source.map((item) => `

${item}

`).join('\n\n'), env), + ).toEqual(expected.map((item) => `

${item}

`).join('\n')) - /* both */ - // relative paths - '', - '', - 'attrs', - // aliases - 'attrs', - 'attrs', - // keep as is - 'attrs', - - /* data uri */ - '', - ] - - const TEST_CASES: { - description: string - md: MarkdownIt - env: MarkdownEnv - expected: string[] - }[] = [ - { - description: 'should handle assets link with default options', - md: MarkdownIt({ html: true }).use(assetsPlugin), - env: { - filePathRelative: 'sub/foo.md', - }, - expected: [ - /* src */ - // relative paths - '', - '', - '', - '', - '', - '', - '', - '', - 'attrs', - // aliases - '', - '', - '', - 'attrs', - // webpack legacy aliases - '', - '', - '', - 'attrs', - // absolute paths - '', - '', - // no-prefix paths - '', - '', - 'attrs', - // keep as is - '', - '', - // invalid paths - '', - '', - '', - 'attrs', - - /* srcset */ - // relative paths - '', - '', - 'attrs', - // aliases - '', - 'attrs', - // webpack legacy aliases - '', - 'attrs', - // keep as is - '', - '', - 'attrs', - // invalid paths - '', - 'attrs', - // invalid srcset - '', - - /* both */ - // relative paths - '', - '', - 'attrs', - // aliases - 'attrs', - 'attrs', - // keep as is - 'attrs', - - /* data uri */ - '', - ], - }, - { - description: 'should respect `relativePathPrefix` option', - md: MarkdownIt({ html: true }).use(assetsPlugin, { - relativePathPrefix: '@foo', - }), - env: { - filePathRelative: 'sub/foo.md', - }, - expected: [ - /* src */ - // relative paths - '', - '', - '', - '', - '', - '', - '', - '', - 'attrs', - // aliases - '', - '', - '', - 'attrs', - // webpack legacy aliases - '', - '', - '', - 'attrs', - // absolute paths - '', - '', - // no-prefix paths - '', - '', - 'attrs', - // keep as is - '', - '', - // invalid paths - '', - '', - '', - 'attrs', - - /* srcset */ - // relative paths - '', - '', - 'attrs', - // aliases - '', - 'attrs', - // webpack legacy aliases - '', - 'attrs', - // keep as is - '', - '', - 'attrs', - // invalid paths - '', - 'attrs', - // invalid srcset - '', - - /* both */ - // relative paths - '', - '', - 'attrs', - // aliases - 'attrs', - 'attrs', - // keep as is - 'attrs', - - /* data uri */ - '', - ], - }, - { - description: - 'should not handle relative paths if `env.filePathRelative` is not provided', - md: MarkdownIt({ html: true }).use(assetsPlugin), - env: {}, - expected: [ - /* src */ - // relative paths - '', - '', - '', - '', - '', - '', - '', - '', - 'attrs', - // aliases - '', - '', - '', - 'attrs', - // webpack legacy aliases - '', - '', - '', - 'attrs', - // absolute paths - '', - '', - // no-prefix paths - '', - '', - 'attrs', - // keep as is - '', - '', - // invalid paths - '', - '', - '', - 'attrs', - - /* srcset */ - // relative paths - '', - '', - 'attrs', - // aliases - '', - 'attrs', - // webpack legacy aliases - '', - 'attrs', - // keep as is - '', - '', - 'attrs', - // invalid paths - '', - 'attrs', - // invalid srcset - '', - - /* both */ - // relative paths - '', - '', - 'attrs', - // aliases - 'attrs', - 'attrs', - // keep as is - 'attrs', - - /* data uri */ - '', - ], - }, - ] - - TEST_CASES.forEach(({ description, md, env, expected }) => { - it(description, () => { - // block - expect(md.render(source.join('\n\n'), env)).toEqual( - expected.map((item) => item).join('\n'), - ) - - // block with leading white space - expect( - md.render(source.map((item) => ` ${item}`).join('\n\n'), env), - ).toEqual(expected.map((item) => ` ${item}`).join('\n')) - - // inline with prefix - expect( - md.render(source.map((item) => `foo${item}`).join('\n\n'), env), - ).toEqual( - `${expected.map((item) => `

foo${item}

`).join('\n')}\n`, - ) - - // inline with suffix - expect( - md.render(source.map((item) => `${item}foo`).join('\n\n'), env), - ).toEqual( - `${expected.map((item) => `

${item}foo

`).join('\n')}\n`, - ) - - // inline with line break - expect( - md.render( - source.map((item) => item.replace(' `

${item.replace('`) - .join('\n')}\n`, - ) - - // wrapped item - expect( - md.render(source.map((item) => `

${item}

`).join('\n\n'), env), - ).toEqual(expected.map((item) => `

${item}

`).join('\n')) - - // wrapped item with line break - expect( - md.render( - source - .map((item) => `

${item.replace('`) - .join('\n\n'), - env, - ), - ).toEqual( - expected + // wrapped item with line break + expect( + md.render( + source .map((item) => `

${item.replace('`) - .join('\n'), - ) - - // wrapped multiple items - expect( - md.render( - source.map((item) => `

${item}${item}

`).join('\n\n'), - env, - ), - ).toEqual(expected.map((item) => `

${item}${item}

`).join('\n')) - - // deeply wrapped multiple items - expect( - md.render( - source - .map((item) => `

\n\n${item}\n${item}\n\n

`) - .join('\n\n'), - env, - ), - ).toEqual( - expected + .join('\n\n'), + env, + ), + ).toEqual( + expected + .map((item) => `

${item.replace('`) + .join('\n'), + ) + + // wrapped multiple items + expect( + md.render( + source.map((item) => `

${item}${item}

`).join('\n\n'), + env, + ), + ).toEqual(expected.map((item) => `

${item}${item}

`).join('\n')) + + // deeply wrapped multiple items + expect( + md.render( + source .map((item) => `

\n\n${item}\n${item}\n\n

`) - .join('\n'), - ) - }) + .join('\n\n'), + env, + ), + ).toEqual( + expected + .map((item) => `

\n\n${item}\n${item}\n\n

`) + .join('\n'), + ) }) }) + }) - // multi-line `` tag will be wrapped with `

` tag - describe('multi-line', () => { - const source = [ - /* src */ - `attrs`, - /* srcset */ - ``, - `attrs`, - /** both */ - ``, - `attrs`, - ] - - const TEST_CASES: { - description: string - md: MarkdownIt - env: MarkdownEnv - expected: string[] - }[] = [ - { - description: 'should handle assets link with default options', - md: MarkdownIt({ html: true }).use(assetsPlugin), - env: { - filePathRelative: 'sub/foo.md', - }, - expected: [ - /* src */ - '

attrs

', - - /* srcset */ - '

', - '

attrs

', - - /* both */ - '

', - '

attrs

', - ], - }, - { - description: 'should respect `relativePathPrefix` option', - md: MarkdownIt({ html: true }).use(assetsPlugin, { - relativePathPrefix: '@foo', - }), - env: { - filePathRelative: 'sub/foo.md', - }, - expected: [ - /* src */ - '

attrs

', - - /* srcset */ - '

', - '

attrs

', - - /* both */ - '

', - '

attrs

', - ], + ] + + const TEST_CASES: { + description: string + md: MarkdownIt + env: MarkdownEnv + expected: string[] + }[] = [ + { + description: 'should handle assets link with default options', + md: MarkdownIt({ html: true }).use(assetsPlugin), + env: { + filePathRelative: 'sub/foo.md', }, - { - description: - 'should not handle assets link if `filePathRelative` is not provided', - md: MarkdownIt({ html: true }).use(assetsPlugin), - env: {}, - expected: [ - /* src */ - '

attrs

', - - /* srcset */ - '

', - '

attrs

', - - /* both */ - '

', - '

attrs

', - ], + expected: [ + /* src */ + '

attrs

', + + /* srcset */ + '

', + '

attrs

', + + /* both */ + '

', + '

attrs

', + ], + }, + { + description: 'should respect `relativePathPrefix` option', + md: MarkdownIt({ html: true }).use(assetsPlugin, { + relativePathPrefix: '@foo', + }), + env: { + filePathRelative: 'sub/foo.md', }, - ] - - TEST_CASES.forEach(({ description, md, env, expected }) => { - it(description, () => { - // double quote - expect(md.render(source.join('\n\n'), env)).toEqual( - `${expected.map((item) => item).join('\n')}\n`, - ) - // single quote - expect( - md.render(source.join('\n\n').replace(/"/g, "'"), env), - ).toEqual( - `${expected.map((item) => item.replace(/"/g, "'")).join('\n')}\n`, - ) - }) + expected: [ + /* src */ + '

attrs

', + + /* srcset */ + '

', + '

attrs

', + + /* both */ + '

', + '

attrs

', + ], + }, + { + description: + 'should not handle assets link if `filePathRelative` is not provided', + md: MarkdownIt({ html: true }).use(assetsPlugin), + env: {}, + expected: [ + /* src */ + '

attrs

', + + /* srcset */ + '

', + '

attrs

', + + /* both */ + '

', + '

attrs

', + ], + }, + ] + + TEST_CASES.forEach(({ description, md, env, expected }) => { + it(description, () => { + // double quote + expect(md.render(source.join('\n\n'), env)).toEqual( + `${expected.map((item) => item).join('\n')}\n`, + ) + // single quote + expect(md.render(source.join('\n\n').replace(/"/g, "'"), env)).toEqual( + `${expected.map((item) => item.replace(/"/g, "'")).join('\n')}\n`, + ) }) }) }) diff --git a/packages/markdown/tests/plugins/importCodePlugin.spec.ts b/packages/markdown/tests/plugins/importCodePlugin.spec.ts index 08c1d481f7..61f9068907 100644 --- a/packages/markdown/tests/plugins/importCodePlugin.spec.ts +++ b/packages/markdown/tests/plugins/importCodePlugin.spec.ts @@ -34,37 +34,36 @@ afterAll(() => { console.error = consoleError }) -describe('@vuepress/markdown > plugins > importCodePlugin', () => { - it('should not be parsed as import code syntax', () => { - const source = [ - '@[cod', - '@[code', - '@[code]', - '@[code](./foo.js', - '@[code](/path/to/foo.js', - '@[coda](/path/to/foo.js', - ] - - const md = MarkdownIt().use(importCodePlugin) - const env: MarkdownEnv = { - filePath: __filename, - } - const rendered = md.render(source.join('\n\n'), env) - - expect(rendered).toEqual( - `${source.map((item) => `

${item}

`).join('\n')}\n`, - ) - expect(env.importedFiles).toBeUndefined() - }) +it('should not be parsed as import code syntax', () => { + const source = [ + '@[cod', + '@[code', + '@[code]', + '@[code](./foo.js', + '@[code](/path/to/foo.js', + '@[coda](/path/to/foo.js', + ] + + const md = MarkdownIt().use(importCodePlugin) + const env: MarkdownEnv = { + filePath: __filename, + } + const rendered = md.render(source.join('\n\n'), env) + + expect(rendered).toEqual( + `${source.map((item) => `

${item}

`).join('\n')}\n`, + ) + expect(env.importedFiles).toBeUndefined() +}) - describe('lines range', () => { - it('should import all lines', () => { - const source = `\ +describe('lines range', () => { + it('should import all lines', () => { + const source = `\ @[code](${JS_FIXTURE_PATH_RELATIVE}) @[code](${MD_FIXTURE_PATH_RELATIVE}) ` - const expected = `\ + const expected = `\
\
 ${JS_FIXTURE_CONTENT}\
 
@@ -73,18 +72,18 @@ ${MD_FIXTURE_CONTENT}\
` - const md = MarkdownIt().use(importCodePlugin) - const env: MarkdownEnv = { - filePath: __filename, - } - const rendered = md.render(source, env) + const md = MarkdownIt().use(importCodePlugin) + const env: MarkdownEnv = { + filePath: __filename, + } + const rendered = md.render(source, env) - expect(rendered).toEqual(expected) - expect(env.importedFiles).toEqual([JS_FIXTURE_PATH, MD_FIXTURE_PATH]) - }) + expect(rendered).toEqual(expected) + expect(env.importedFiles).toEqual([JS_FIXTURE_PATH, MD_FIXTURE_PATH]) + }) - it('should import partial lines', () => { - const source = `\ + it('should import partial lines', () => { + const source = `\ @[code{1-2}](${JS_FIXTURE_PATH_RELATIVE}) @[code{1-}](${JS_FIXTURE_PATH_RELATIVE}) @[code{2}](${JS_FIXTURE_PATH_RELATIVE}) @@ -93,7 +92,7 @@ ${MD_FIXTURE_CONTENT}\ @[code{5}](${MD_FIXTURE_PATH_RELATIVE}) ` - const expected = `\ + const expected = `\
\
 ${JS_FIXTURE_CONTENT.split('\n').slice(0, 2).join('\n').replace(/\n?$/, '\n')}\
 
@@ -114,246 +113,245 @@ ${MD_FIXTURE_CONTENT.split('\n').slice(4, 5).join('\n').replace(/\n?$/, '\n')}\
` - const md = MarkdownIt().use(importCodePlugin) - const env: MarkdownEnv = { - filePath: __filename, - } - const rendered = md.render(source, env) - - expect(rendered).toEqual(expected) - expect(env.importedFiles).toEqual([ - JS_FIXTURE_PATH, - JS_FIXTURE_PATH, - JS_FIXTURE_PATH, - MD_FIXTURE_PATH, - MD_FIXTURE_PATH, - MD_FIXTURE_PATH, - ]) - }) + const md = MarkdownIt().use(importCodePlugin) + const env: MarkdownEnv = { + filePath: __filename, + } + const rendered = md.render(source, env) + + expect(rendered).toEqual(expected) + expect(env.importedFiles).toEqual([ + JS_FIXTURE_PATH, + JS_FIXTURE_PATH, + JS_FIXTURE_PATH, + MD_FIXTURE_PATH, + MD_FIXTURE_PATH, + MD_FIXTURE_PATH, + ]) }) +}) - describe('code language', () => { - it('should use user defined language', () => { - const source = `\ +describe('code language', () => { + it('should use user defined language', () => { + const source = `\ @[code](/foo.js) @[code ts](/bar.md) ` - const expected = `\ + const expected = `\
File not found
File not found
` - const md = MarkdownIt().use(importCodePlugin) - const env: MarkdownEnv = { - filePath: __filename, - } - const rendered = md.render(source, env) + const md = MarkdownIt().use(importCodePlugin) + const env: MarkdownEnv = { + filePath: __filename, + } + const rendered = md.render(source, env) - expect(rendered).toEqual(expected) - expect(env.importedFiles).toEqual(['/foo.js', '/bar.md']) - expect(mockConsoleError).toHaveBeenCalledTimes(2) - }) + expect(rendered).toEqual(expected) + expect(env.importedFiles).toEqual(['/foo.js', '/bar.md']) + expect(mockConsoleError).toHaveBeenCalledTimes(2) + }) - it('should use file ext as fallback language', () => { - const source = `\ + it('should use file ext as fallback language', () => { + const source = `\ @[code](/foo.js) @[code](/bar.md) ` - const expected = `\ + const expected = `\
File not found
File not found
` - const md = MarkdownIt().use(importCodePlugin) - const env: MarkdownEnv = { - filePath: __filename, - } - const rendered = md.render(source, env) + const md = MarkdownIt().use(importCodePlugin) + const env: MarkdownEnv = { + filePath: __filename, + } + const rendered = md.render(source, env) - expect(rendered).toEqual(expected) - expect(env.importedFiles).toEqual(['/foo.js', '/bar.md']) - expect(mockConsoleError).toHaveBeenCalledTimes(2) - }) + expect(rendered).toEqual(expected) + expect(env.importedFiles).toEqual(['/foo.js', '/bar.md']) + expect(mockConsoleError).toHaveBeenCalledTimes(2) }) +}) - describe('path resolving', () => { - it('should resolve relative path according to filePath', () => { - const source = `\ +describe('path resolving', () => { + it('should resolve relative path according to filePath', () => { + const source = `\ @[code](/foo.js) @[code](./bar.js) ` - const expected = `\ + const expected = `\
File not found
File not found
` - const md = MarkdownIt().use(importCodePlugin) - const env: MarkdownEnv = { - filePath: __filename, - } - const rendered = md.render(source, env) - - expect(rendered).toEqual(expected) - expect(env.importedFiles).toEqual([ - '/foo.js', - path.resolve(__dirname, './bar.js'), - ]) - expect(mockConsoleError).toHaveBeenCalledTimes(2) - }) + const md = MarkdownIt().use(importCodePlugin) + const env: MarkdownEnv = { + filePath: __filename, + } + const rendered = md.render(source, env) + + expect(rendered).toEqual(expected) + expect(env.importedFiles).toEqual([ + '/foo.js', + path.resolve(__dirname, './bar.js'), + ]) + expect(mockConsoleError).toHaveBeenCalledTimes(2) + }) - it('should not resolve relative path if filePath is not provided', () => { - const source = `\ + it('should not resolve relative path if filePath is not provided', () => { + const source = `\ @[code](/foo.js) @[code](./bar.js) ` - const expected = `\ + const expected = `\
File not found
Error when resolving path
` - const md = MarkdownIt().use(importCodePlugin) - const env: MarkdownEnv = { - filePath: null, - } - const rendered = md.render(source, env) + const md = MarkdownIt().use(importCodePlugin) + const env: MarkdownEnv = { + filePath: null, + } + const rendered = md.render(source, env) - expect(rendered).toEqual(expected) - expect(env.importedFiles).toEqual(['/foo.js']) - expect(mockConsoleError).toHaveBeenCalledTimes(2) - }) + expect(rendered).toEqual(expected) + expect(env.importedFiles).toEqual(['/foo.js']) + expect(mockConsoleError).toHaveBeenCalledTimes(2) + }) - it('should handle import path correctly', () => { - const source = `\ + it('should handle import path correctly', () => { + const source = `\ @[code](@fixtures/importCode.js) ` - const expected = `\ + const expected = `\
\
 ${JS_FIXTURE_CONTENT}\
 
` - const md = MarkdownIt().use(importCodePlugin, { - handleImportPath: (str: string): string => - str.replace(/^@fixtures/, path.resolve(__dirname, '../__fixtures__')), - }) - const env: MarkdownEnv = { - filePath: null, - } - const rendered = md.render(source, env) - - expect(rendered).toEqual(expected) - expect(env.importedFiles).toEqual([JS_FIXTURE_PATH]) + const md = MarkdownIt().use(importCodePlugin, { + handleImportPath: (str: string): string => + str.replace(/^@fixtures/, path.resolve(__dirname, '../__fixtures__')), }) + const env: MarkdownEnv = { + filePath: null, + } + const rendered = md.render(source, env) + + expect(rendered).toEqual(expected) + expect(env.importedFiles).toEqual([JS_FIXTURE_PATH]) }) +}) - describe('compatibility with other markdown syntax', () => { - it('should terminate paragraph', () => { - const source = `\ +describe('compatibility with other markdown syntax', () => { + it('should terminate paragraph', () => { + const source = `\ foo @[code](/path/to/foo.js) ` - const expected = `\ + const expected = `\

foo

File not found
` - const md = MarkdownIt().use(importCodePlugin) - const env: MarkdownEnv = { - filePath: __filename, - } - const rendered = md.render(source, env) + const md = MarkdownIt().use(importCodePlugin) + const env: MarkdownEnv = { + filePath: __filename, + } + const rendered = md.render(source, env) - expect(rendered).toEqual(expected) - expect(env.importedFiles).toEqual(['/path/to/foo.js']) - expect(mockConsoleError).toHaveBeenCalledTimes(1) - }) + expect(rendered).toEqual(expected) + expect(env.importedFiles).toEqual(['/path/to/foo.js']) + expect(mockConsoleError).toHaveBeenCalledTimes(1) + }) - it('should terminate blockquote', () => { - const source = `\ + it('should terminate blockquote', () => { + const source = `\ > foo @[code](/path/to/foo.js) ` - const expected = `\ + const expected = `\

foo

File not found
` - const md = MarkdownIt().use(importCodePlugin) - const env: MarkdownEnv = { - filePath: __filename, - } - const rendered = md.render(source, env) + const md = MarkdownIt().use(importCodePlugin) + const env: MarkdownEnv = { + filePath: __filename, + } + const rendered = md.render(source, env) - expect(rendered).toEqual(expected) - expect(env.importedFiles).toEqual(['/path/to/foo.js']) - expect(mockConsoleError).toHaveBeenCalledTimes(1) - }) + expect(rendered).toEqual(expected) + expect(env.importedFiles).toEqual(['/path/to/foo.js']) + expect(mockConsoleError).toHaveBeenCalledTimes(1) }) +}) - describe('compatibility with otherPlugin', () => { - it('should preserve the things after code as fence info', () => { - const source1 = `\ +describe('compatibility with otherPlugin', () => { + it('should preserve the things after code as fence info', () => { + const source1 = `\ @[code js{1,3-4}](${JS_FIXTURE_PATH_RELATIVE}) ` - const source2 = `\ + const source2 = `\ @[code md:no-line-numbers:no-v-pre title="no-line-numbers.md"](${MD_FIXTURE_PATH_RELATIVE}) ` - const md = MarkdownIt().use(importCodePlugin) - const env1: MarkdownEnv = { - filePath: __filename, - } + const md = MarkdownIt().use(importCodePlugin) + const env1: MarkdownEnv = { + filePath: __filename, + } - const rendered1 = md.render(source1, env1) + const rendered1 = md.render(source1, env1) - expect(rendered1).toEqual( - md.render(`\ + expect(rendered1).toEqual( + md.render(`\ \`\`\`js{1,3-4} ${JS_FIXTURE_CONTENT}\ \`\`\` `), - ) - expect(rendered1).toMatchSnapshot() - expect(env1.importedFiles).toEqual([JS_FIXTURE_PATH]) + ) + expect(rendered1).toMatchSnapshot() + expect(env1.importedFiles).toEqual([JS_FIXTURE_PATH]) - const env2: MarkdownEnv = { - filePath: __filename, - } + const env2: MarkdownEnv = { + filePath: __filename, + } - const rendered2 = md.render(source2, env2) + const rendered2 = md.render(source2, env2) - expect(rendered2).toEqual( - md.render(`\ + expect(rendered2).toEqual( + md.render(`\ \`\`\`md:no-line-numbers:no-v-pre title="no-line-numbers.md" ${MD_FIXTURE_CONTENT}\ \`\`\` `), - ) - expect(rendered2).toMatchSnapshot() - expect(env2.importedFiles).toEqual([MD_FIXTURE_PATH]) - }) + ) + expect(rendered2).toMatchSnapshot() + expect(env2.importedFiles).toEqual([MD_FIXTURE_PATH]) + }) - it('should work with syntax supported by vPrePlugin', () => { - const source1 = `\ + it('should work with syntax supported by vPrePlugin', () => { + const source1 = `\ @[code js{1,3-4}](${JS_FIXTURE_PATH_RELATIVE}) ` - const source2 = `\ + const source2 = `\ @[code md:no-line-numbers:no-v-pre title="no-line-numbers.md"](${MD_FIXTURE_PATH_RELATIVE}) ` - const md = MarkdownIt().use(importCodePlugin).use(vPrePlugin) - const env: MarkdownEnv = { - filePath: __filename, - } + const md = MarkdownIt().use(importCodePlugin).use(vPrePlugin) + const env: MarkdownEnv = { + filePath: __filename, + } - const rendered1 = md.render(source1, env) - const rendered2 = md.render(source2, env) + const rendered1 = md.render(source1, env) + const rendered2 = md.render(source2, env) - expect(rendered1).to.contain('v-pre') - expect(rendered2).to.not.contain(' v-pre') - }) + expect(rendered1).to.contain('v-pre') + expect(rendered2).to.not.contain(' v-pre') }) }) diff --git a/packages/markdown/tests/plugins/linksPlugin.spec.ts b/packages/markdown/tests/plugins/linksPlugin.spec.ts index b74996ac9d..17911a6f48 100644 --- a/packages/markdown/tests/plugins/linksPlugin.spec.ts +++ b/packages/markdown/tests/plugins/linksPlugin.spec.ts @@ -3,744 +3,742 @@ import { describe, expect, it } from 'vitest' import type { MarkdownEnv } from '../../src/index.js' import { linksPlugin } from '../../src/index.js' -describe('@vuepress/markdown > plugins > linksPlugin', () => { - describe('external links', () => { - describe('protocol links', () => { - const source = [ - '[https-github](https://github.com)', - '[http-github](http://github.com)', - '[github](//github.com)', - '[https-github-md](https://github.com/foo/bar/blob/main/README.md)', - '[http-github-md](http://github.com/foo/bar/blob/main/README.md)', - '[github-md](//github.com/foo/bar/blob/main/README.md)', - // autolink - '', - '', - '', - '', - ].join('\n\n') - - it('should render default attrs', () => { - const md = MarkdownIt({ html: true }).use(linksPlugin) - const env: MarkdownEnv = {} - - const rendered = md.render(source, env) - - expect(rendered).toEqual( - [ - 'https-github', - 'http-github', - 'github', - 'https-github-md', - 'http-github-md', - 'github-md', - 'https://github.com', - 'http://github.com', - 'https://github.com/foo/bar/blob/main/README.md', - 'http://github.com/foo/bar/blob/main/README.md', - ] - .map((a) => `

${a}

`) - .join('\n') + '\n', - ) - - expect(env.links).toBeUndefined() - }) +describe('external links', () => { + describe('protocol links', () => { + const source = [ + '[https-github](https://github.com)', + '[http-github](http://github.com)', + '[github](//github.com)', + '[https-github-md](https://github.com/foo/bar/blob/main/README.md)', + '[http-github-md](http://github.com/foo/bar/blob/main/README.md)', + '[github-md](//github.com/foo/bar/blob/main/README.md)', + // autolink + '', + '', + '', + '', + ].join('\n\n') + + it('should render default attrs', () => { + const md = MarkdownIt({ html: true }).use(linksPlugin) + const env: MarkdownEnv = {} - it('should add extra attrs', () => { - const md = MarkdownIt({ html: true }).use(linksPlugin, { - externalAttrs: { - foo: 'bar', - }, - }) - const env: MarkdownEnv = {} - - const rendered = md.render(source, env) - - expect(rendered).toEqual( - [ - 'https-github', - 'http-github', - 'github', - 'https-github-md', - 'http-github-md', - 'github-md', - 'https://github.com', - 'http://github.com', - 'https://github.com/foo/bar/blob/main/README.md', - 'http://github.com/foo/bar/blob/main/README.md', - ] - .map((a) => `

${a}

`) - .join('\n') + '\n', - ) - expect(env.links).toBeUndefined() - }) + const rendered = md.render(source, env) + + expect(rendered).toEqual( + [ + 'https-github', + 'http-github', + 'github', + 'https-github-md', + 'http-github-md', + 'github-md', + 'https://github.com', + 'http://github.com', + 'https://github.com/foo/bar/blob/main/README.md', + 'http://github.com/foo/bar/blob/main/README.md', + ] + .map((a) => `

${a}

`) + .join('\n') + '\n', + ) + + expect(env.links).toBeUndefined() + }) - it('should override default attrs', () => { - const md = MarkdownIt({ html: true }).use(linksPlugin, { - externalAttrs: { - rel: 'foobar', - }, - }) - const env: MarkdownEnv = {} - - const rendered = md.render(source, env) - - expect(rendered).toEqual( - [ - 'https-github', - 'http-github', - 'github', - 'https-github-md', - 'http-github-md', - 'github-md', - 'https://github.com', - 'http://github.com', - 'https://github.com/foo/bar/blob/main/README.md', - 'http://github.com/foo/bar/blob/main/README.md', - ] - .map((a) => `

${a}

`) - .join('\n') + '\n', - ) - expect(env.links).toBeUndefined() + it('should add extra attrs', () => { + const md = MarkdownIt({ html: true }).use(linksPlugin, { + externalAttrs: { + foo: 'bar', + }, }) + const env: MarkdownEnv = {} + + const rendered = md.render(source, env) + + expect(rendered).toEqual( + [ + 'https-github', + 'http-github', + 'github', + 'https-github-md', + 'http-github-md', + 'github-md', + 'https://github.com', + 'http://github.com', + 'https://github.com/foo/bar/blob/main/README.md', + 'http://github.com/foo/bar/blob/main/README.md', + ] + .map((a) => `

${a}

`) + .join('\n') + '\n', + ) + expect(env.links).toBeUndefined() }) - describe('absolute links', () => { - const source = [ - '[html](/path/to/index.html)', - '[pdf](/path/to/index.pdf)', - '[png](/path/to/index.png)', - ].join('\n\n') - - it('should render default attrs', () => { - const md = MarkdownIt({ html: true }).use(linksPlugin) - const env: MarkdownEnv = { - base: '/base/', - } - - const rendered = md.render(source, env) - - expect(rendered).toEqual( - [ - 'html', - 'pdf', - 'png', - ] - .map((a) => `

${a}

`) - .join('\n') + '\n', - ) - - expect(env.links).toBeUndefined() + it('should override default attrs', () => { + const md = MarkdownIt({ html: true }).use(linksPlugin, { + externalAttrs: { + rel: 'foobar', + }, }) + const env: MarkdownEnv = {} + + const rendered = md.render(source, env) + + expect(rendered).toEqual( + [ + 'https-github', + 'http-github', + 'github', + 'https-github-md', + 'http-github-md', + 'github-md', + 'https://github.com', + 'http://github.com', + 'https://github.com/foo/bar/blob/main/README.md', + 'http://github.com/foo/bar/blob/main/README.md', + ] + .map((a) => `

${a}

`) + .join('\n') + '\n', + ) + expect(env.links).toBeUndefined() }) }) - describe('internal links', () => { - describe('relative links', () => { - const source = [ - '[foo1](foo.md)', - '[foo2](./foo.md)', - '[bar1](../bar.md)', - '[bar2](./../bar.md)', - '[foobar1](foo/bar.md)', - '[foobar2](../foo/bar.md)', - '[index1](index.md)', - '[index2](./index.md)', - '[index3](../index.md)', - '[index4](../foo/bar/index.md)', - '[readme1](readme.md)', - '[readme2](../foo/bar/readme.md)', - ] - .flatMap((item) => { - const link = /([^)]*)/.exec(item)![1] - - return [ - item, - item.replace(link, `${link}#hash`), - item.replace(link, `${link}?a=1&b=2`), - item.replace(link, `${link}#hash?a=1&b=2`), - item.replace(link, `${link}?a=1&b=2#hash`), - ] - }) - .join('\n\n') - - const expectRelativeLinks = [ - { - raw: 'foo.md', - relative: 'foo.md', - absolute: null, - }, - { - raw: './foo.md', - relative: 'foo.md', - absolute: null, - }, - { - raw: '../bar.md', - relative: '../bar.md', - absolute: null, - }, - { - raw: './../bar.md', - relative: '../bar.md', - absolute: null, - }, - { - raw: 'foo/bar.md', - relative: 'foo/bar.md', - absolute: null, - }, - { - raw: '../foo/bar.md', - relative: '../foo/bar.md', - absolute: null, - }, - { - raw: 'index.md', - relative: 'index.md', - absolute: null, - }, - { - raw: './index.md', - relative: 'index.md', - absolute: null, - }, - { - raw: '../index.md', - relative: '../index.md', - absolute: null, - }, - { - raw: '../foo/bar/index.md', - relative: '../foo/bar/index.md', - absolute: null, - }, - { - raw: 'readme.md', - relative: 'readme.md', - absolute: null, - }, - { - raw: '../foo/bar/readme.md', - relative: '../foo/bar/readme.md', - absolute: null, - }, - ].flatMap(({ raw, ...rest }) => [ - { raw, ...rest }, - { raw: `${raw}#hash`, ...rest }, - { raw: `${raw}?a=1&b=2`, ...rest }, - { raw: `${raw}#hash?a=1&b=2`, ...rest }, - { raw: `${raw}?a=1&b=2#hash`, ...rest }, - ]) + describe('absolute links', () => { + const source = [ + '[html](/path/to/index.html)', + '[pdf](/path/to/index.pdf)', + '[png](/path/to/index.png)', + ].join('\n\n') - it('should render to tag correctly', () => { - const md = MarkdownIt({ html: true }).use(linksPlugin, { - internalTag: 'a', - }) - const env: MarkdownEnv = {} - - const rendered = md.render(source, env) - - expect(rendered).toEqual( - [ - 'foo1', - 'foo2', - 'bar1', - 'bar2', - 'foobar1', - 'foobar2', - 'index1', - 'index2', - 'index3', - 'index4', - 'readme1', - 'readme2', - ] - .flatMap((item) => { - const link = /href="([^"]*)"/.exec(item)![1] - - return [ - item, - item.replace(link, `${link}#hash`), - item.replace(link, `${link}?a=1&b=2`), - item.replace(link, `${link}#hash?a=1&b=2`), - item.replace(link, `${link}?a=1&b=2#hash`), - ] - }) - .map((a) => `

${a}

`) - .join('\n') + '\n', - ) - - expect(env.links).toEqual(expectRelativeLinks) - }) + it('should render default attrs', () => { + const md = MarkdownIt({ html: true }).use(linksPlugin) + const env: MarkdownEnv = { + base: '/base/', + } + + const rendered = md.render(source, env) + + expect(rendered).toEqual( + [ + 'html', + 'pdf', + 'png', + ] + .map((a) => `

${a}

`) + .join('\n') + '\n', + ) - it('should render relative links correctly', () => { - const md = MarkdownIt({ html: true }).use(linksPlugin) - const env: MarkdownEnv = {} - - const rendered = md.render(source, env) - - expect(rendered).toEqual( - [ - 'foo1', - 'foo2', - 'bar1', - 'bar2', - 'foobar1', - 'foobar2', - 'index1', - 'index2', - 'index3', - 'index4', - 'readme1', - 'readme2', - ] - .flatMap((item) => { - const link = /to="([^"]*)"/.exec(item)![1] - - return [ - item, - item.replace(link, `${link}#hash`), - item.replace(link, `${link}?a=1&b=2`), - item.replace(link, `${link}#hash?a=1&b=2`), - item.replace(link, `${link}?a=1&b=2#hash`), - ] - }) - .map((a) => `

${a}

`) - .join('\n') + '\n', - ) - - expect(env.links).toEqual(expectRelativeLinks) - }) + expect(env.links).toBeUndefined() + }) + }) +}) - it('should convert to absolute links correctly', () => { - const md = MarkdownIt({ html: true }).use(linksPlugin) - const env: MarkdownEnv = { - filePathRelative: 'path/to/file.md', - } - - const rendered = md.render(source, env) - - expect(rendered).toEqual( - [ - 'foo1', - 'foo2', - 'bar1', - 'bar2', - 'foobar1', - 'foobar2', - 'index1', - 'index2', - 'index3', - 'index4', - 'readme1', - 'readme2', - ] - .flatMap((item) => { - const link = /to="([^"]*)"/.exec(item)![1] - - return [ - item, - item.replace(link, `${link}#hash`), - item.replace(link, `${link}?a=1&b=2`), - item.replace(link, `${link}#hash?a=1&b=2`), - item.replace(link, `${link}?a=1&b=2#hash`), - ] - }) - .map((a) => `

${a}

`) - .join('\n') + '\n', - ) - - expect(env.links).toEqual( - [ - { - raw: 'foo.md', - relative: 'path/to/foo.md', - absolute: '/path/to/foo.md', - }, - { - raw: './foo.md', - relative: 'path/to/foo.md', - absolute: '/path/to/foo.md', - }, - { - raw: '../bar.md', - relative: 'path/bar.md', - absolute: '/path/bar.md', - }, - { - raw: './../bar.md', - relative: 'path/bar.md', - absolute: '/path/bar.md', - }, - { - raw: 'foo/bar.md', - relative: 'path/to/foo/bar.md', - absolute: '/path/to/foo/bar.md', - }, - { - raw: '../foo/bar.md', - relative: 'path/foo/bar.md', - absolute: '/path/foo/bar.md', - }, - { - raw: 'index.md', - relative: 'path/to/index.md', - absolute: '/path/to/index.md', - }, - { - raw: './index.md', - relative: 'path/to/index.md', - absolute: '/path/to/index.md', - }, - { - raw: '../index.md', - relative: 'path/index.md', - absolute: '/path/index.md', - }, - { - raw: '../foo/bar/index.md', - relative: 'path/foo/bar/index.md', - absolute: '/path/foo/bar/index.md', - }, - { - raw: 'readme.md', - relative: 'path/to/readme.md', - absolute: '/path/to/readme.md', - }, - { - raw: '../foo/bar/readme.md', - relative: 'path/foo/bar/readme.md', - absolute: '/path/foo/bar/readme.md', - }, - ].flatMap(({ raw, ...rest }) => [ - { raw, ...rest }, - { raw: `${raw}#hash`, ...rest }, - { raw: `${raw}?a=1&b=2`, ...rest }, - { raw: `${raw}#hash?a=1&b=2`, ...rest }, - { raw: `${raw}?a=1&b=2#hash`, ...rest }, - ]), - ) +describe('internal links', () => { + describe('relative links', () => { + const source = [ + '[foo1](foo.md)', + '[foo2](./foo.md)', + '[bar1](../bar.md)', + '[bar2](./../bar.md)', + '[foobar1](foo/bar.md)', + '[foobar2](../foo/bar.md)', + '[index1](index.md)', + '[index2](./index.md)', + '[index3](../index.md)', + '[index4](../foo/bar/index.md)', + '[readme1](readme.md)', + '[readme2](../foo/bar/readme.md)', + ] + .flatMap((item) => { + const link = /([^)]*)/.exec(item)![1] + + return [ + item, + item.replace(link, `${link}#hash`), + item.replace(link, `${link}?a=1&b=2`), + item.replace(link, `${link}#hash?a=1&b=2`), + item.replace(link, `${link}?a=1&b=2#hash`), + ] }) - - it('should convert to absolute links correctly if the file path contains non-ASCII characters', () => { - const md = MarkdownIt({ html: true }).use(linksPlugin) - const env: MarkdownEnv = { - filePathRelative: '中/文/路径.md', - } - const encoded中 = encodeURI('中') - const encoded文 = encodeURI('文') - - const rendered = md.render(source, env) - - expect(rendered).toEqual( - [ - `foo1`, - `foo2`, - `bar1`, - `bar2`, - `foobar1`, - `foobar2`, - `index1`, - `index2`, - `index3`, - `index4`, - `readme1`, - `readme2`, - ] - .flatMap((item) => { - const link = /to="([^"]*)"/.exec(item)![1] - - return [ - item, - item.replace(link, `${link}#hash`), - item.replace(link, `${link}?a=1&b=2`), - item.replace(link, `${link}#hash?a=1&b=2`), - item.replace(link, `${link}?a=1&b=2#hash`), - ] - }) - .map((a) => `

${a}

`) - .join('\n') + '\n', - ) - - expect(env.links).toEqual( - [ - { - raw: 'foo.md', - relative: `${encoded中}/${encoded文}/foo.md`, - absolute: `/${encoded中}/${encoded文}/foo.md`, - }, - { - raw: './foo.md', - relative: `${encoded中}/${encoded文}/foo.md`, - absolute: `/${encoded中}/${encoded文}/foo.md`, - }, - { - raw: '../bar.md', - relative: `${encoded中}/bar.md`, - absolute: `/${encoded中}/bar.md`, - }, - { - raw: './../bar.md', - relative: `${encoded中}/bar.md`, - absolute: `/${encoded中}/bar.md`, - }, - { - raw: 'foo/bar.md', - relative: `${encoded中}/${encoded文}/foo/bar.md`, - absolute: `/${encoded中}/${encoded文}/foo/bar.md`, - }, - { - raw: '../foo/bar.md', - relative: `${encoded中}/foo/bar.md`, - absolute: `/${encoded中}/foo/bar.md`, - }, - { - raw: 'index.md', - relative: `${encoded中}/${encoded文}/index.md`, - absolute: `/${encoded中}/${encoded文}/index.md`, - }, - { - raw: './index.md', - relative: `${encoded中}/${encoded文}/index.md`, - absolute: `/${encoded中}/${encoded文}/index.md`, - }, - { - raw: '../index.md', - relative: `${encoded中}/index.md`, - absolute: `/${encoded中}/index.md`, - }, - { - raw: '../foo/bar/index.md', - relative: `${encoded中}/foo/bar/index.md`, - absolute: `/${encoded中}/foo/bar/index.md`, - }, - { - raw: 'readme.md', - relative: `${encoded中}/${encoded文}/readme.md`, - absolute: `/${encoded中}/${encoded文}/readme.md`, - }, - { - raw: '../foo/bar/readme.md', - relative: `${encoded中}/foo/bar/readme.md`, - absolute: `/${encoded中}/foo/bar/readme.md`, - }, - ].flatMap(({ raw, ...rest }) => [ - { raw, ...rest }, - { raw: `${raw}#hash`, ...rest }, - { raw: `${raw}?a=1&b=2`, ...rest }, - { raw: `${raw}#hash?a=1&b=2`, ...rest }, - { raw: `${raw}?a=1&b=2#hash`, ...rest }, - ]), - ) + .join('\n\n') + + const expectRelativeLinks = [ + { + raw: 'foo.md', + relative: 'foo.md', + absolute: null, + }, + { + raw: './foo.md', + relative: 'foo.md', + absolute: null, + }, + { + raw: '../bar.md', + relative: '../bar.md', + absolute: null, + }, + { + raw: './../bar.md', + relative: '../bar.md', + absolute: null, + }, + { + raw: 'foo/bar.md', + relative: 'foo/bar.md', + absolute: null, + }, + { + raw: '../foo/bar.md', + relative: '../foo/bar.md', + absolute: null, + }, + { + raw: 'index.md', + relative: 'index.md', + absolute: null, + }, + { + raw: './index.md', + relative: 'index.md', + absolute: null, + }, + { + raw: '../index.md', + relative: '../index.md', + absolute: null, + }, + { + raw: '../foo/bar/index.md', + relative: '../foo/bar/index.md', + absolute: null, + }, + { + raw: 'readme.md', + relative: 'readme.md', + absolute: null, + }, + { + raw: '../foo/bar/readme.md', + relative: '../foo/bar/readme.md', + absolute: null, + }, + ].flatMap(({ raw, ...rest }) => [ + { raw, ...rest }, + { raw: `${raw}#hash`, ...rest }, + { raw: `${raw}?a=1&b=2`, ...rest }, + { raw: `${raw}#hash?a=1&b=2`, ...rest }, + { raw: `${raw}?a=1&b=2#hash`, ...rest }, + ]) + + it('should render to tag correctly', () => { + const md = MarkdownIt({ html: true }).use(linksPlugin, { + internalTag: 'a', }) + const env: MarkdownEnv = {} - it('should not conflict with base', () => { - const md = MarkdownIt({ html: true }).use(linksPlugin) - const env: MarkdownEnv = { - base: '/path/', - filePathRelative: 'path/to/file.md', - } - - const rendered = md.render(source, env) - - expect(rendered).toEqual( - [ - 'foo1', - 'foo2', - 'bar1', - 'bar2', - 'foobar1', - 'foobar2', - 'index1', - 'index2', - 'index3', - 'index4', - 'readme1', - 'readme2', - ] - .flatMap((item) => { - const link = /to="([^"]*)"/.exec(item)![1] - - return [ - item, - item.replace(link, `${link}#hash`), - item.replace(link, `${link}?a=1&b=2`), - item.replace(link, `${link}#hash?a=1&b=2`), - item.replace(link, `${link}?a=1&b=2#hash`), - ] - }) - .map((a) => `

${a}

`) - .join('\n') + '\n', - ) - - expect(env.links).toEqual( - [ - { - raw: 'foo.md', - relative: 'path/to/foo.md', - absolute: '/path/path/to/foo.md', - }, - { - raw: './foo.md', - relative: 'path/to/foo.md', - absolute: '/path/path/to/foo.md', - }, - { - raw: '../bar.md', - relative: 'path/bar.md', - absolute: '/path/path/bar.md', - }, - { - raw: './../bar.md', - relative: 'path/bar.md', - absolute: '/path/path/bar.md', - }, - { - raw: 'foo/bar.md', - relative: 'path/to/foo/bar.md', - absolute: '/path/path/to/foo/bar.md', - }, - { - raw: '../foo/bar.md', - relative: 'path/foo/bar.md', - absolute: '/path/path/foo/bar.md', - }, - { - raw: 'index.md', - relative: 'path/to/index.md', - absolute: '/path/path/to/index.md', - }, - { - raw: './index.md', - relative: 'path/to/index.md', - absolute: '/path/path/to/index.md', - }, - { - raw: '../index.md', - relative: 'path/index.md', - absolute: '/path/path/index.md', - }, - { - raw: '../foo/bar/index.md', - relative: 'path/foo/bar/index.md', - absolute: '/path/path/foo/bar/index.md', - }, - { - raw: 'readme.md', - relative: 'path/to/readme.md', - absolute: '/path/path/to/readme.md', - }, - { - raw: '../foo/bar/readme.md', - relative: 'path/foo/bar/readme.md', - absolute: '/path/path/foo/bar/readme.md', - }, - ].flatMap(({ raw, ...rest }) => [ - { raw, ...rest }, - { raw: `${raw}#hash`, ...rest }, - { raw: `${raw}?a=1&b=2`, ...rest }, - { raw: `${raw}#hash?a=1&b=2`, ...rest }, - { raw: `${raw}?a=1&b=2#hash`, ...rest }, - ]), - ) - }) + const rendered = md.render(source, env) + + expect(rendered).toEqual( + [ + '
foo1', + 'foo2', + 'bar1', + 'bar2', + 'foobar1', + 'foobar2', + 'index1', + 'index2', + 'index3', + 'index4', + 'readme1', + 'readme2', + ] + .flatMap((item) => { + const link = /href="([^"]*)"/.exec(item)![1] + + return [ + item, + item.replace(link, `${link}#hash`), + item.replace(link, `${link}?a=1&b=2`), + item.replace(link, `${link}#hash?a=1&b=2`), + item.replace(link, `${link}?a=1&b=2#hash`), + ] + }) + .map((a) => `

${a}

`) + .join('\n') + '\n', + ) + + expect(env.links).toEqual(expectRelativeLinks) }) - describe('absolute links', () => { - const source = [ - '[md](/path/to/index.md)', - '[md-with-redundant-base](/base/path/to/index.md)', - '[html](/base/path/to/index.html)', - ].join('\n\n') - - it('should resolve to internal links correctly', () => { - const md = MarkdownIt({ html: true }).use(linksPlugin) - const env: MarkdownEnv = { - base: '/base/', - } - - const rendered = md.render(source, env) - - expect(rendered).toEqual( - [ - 'md', - 'md-with-redundant-base', - 'html', - ] - .map((a) => `

${a}

`) - .join('\n') + '\n', - ) - - expect(env.links).toEqual([ - { - raw: '/path/to/index.md', + it('should render relative links correctly', () => { + const md = MarkdownIt({ html: true }).use(linksPlugin) + const env: MarkdownEnv = {} + + const rendered = md.render(source, env) + + expect(rendered).toEqual( + [ + 'foo1', + 'foo2', + 'bar1', + 'bar2', + 'foobar1', + 'foobar2', + 'index1', + 'index2', + 'index3', + 'index4', + 'readme1', + 'readme2', + ] + .flatMap((item) => { + const link = /to="([^"]*)"/.exec(item)![1] + + return [ + item, + item.replace(link, `${link}#hash`), + item.replace(link, `${link}?a=1&b=2`), + item.replace(link, `${link}#hash?a=1&b=2`), + item.replace(link, `${link}?a=1&b=2#hash`), + ] + }) + .map((a) => `

${a}

`) + .join('\n') + '\n', + ) + + expect(env.links).toEqual(expectRelativeLinks) + }) + + it('should convert to absolute links correctly', () => { + const md = MarkdownIt({ html: true }).use(linksPlugin) + const env: MarkdownEnv = { + filePathRelative: 'path/to/file.md', + } + + const rendered = md.render(source, env) + + expect(rendered).toEqual( + [ + 'foo1', + 'foo2', + 'bar1', + 'bar2', + 'foobar1', + 'foobar2', + 'index1', + 'index2', + 'index3', + 'index4', + 'readme1', + 'readme2', + ] + .flatMap((item) => { + const link = /to="([^"]*)"/.exec(item)![1] + + return [ + item, + item.replace(link, `${link}#hash`), + item.replace(link, `${link}?a=1&b=2`), + item.replace(link, `${link}#hash?a=1&b=2`), + item.replace(link, `${link}?a=1&b=2#hash`), + ] + }) + .map((a) => `

${a}

`) + .join('\n') + '\n', + ) + + expect(env.links).toEqual( + [ + { + raw: 'foo.md', + relative: 'path/to/foo.md', + absolute: '/path/to/foo.md', + }, + { + raw: './foo.md', + relative: 'path/to/foo.md', + absolute: '/path/to/foo.md', + }, + { + raw: '../bar.md', + relative: 'path/bar.md', + absolute: '/path/bar.md', + }, + { + raw: './../bar.md', + relative: 'path/bar.md', + absolute: '/path/bar.md', + }, + { + raw: 'foo/bar.md', + relative: 'path/to/foo/bar.md', + absolute: '/path/to/foo/bar.md', + }, + { + raw: '../foo/bar.md', + relative: 'path/foo/bar.md', + absolute: '/path/foo/bar.md', + }, + { + raw: 'index.md', relative: 'path/to/index.md', - absolute: '/base/path/to/index.md', + absolute: '/path/to/index.md', }, { - raw: '/base/path/to/index.md', - relative: 'base/path/to/index.md', - absolute: '/base/base/path/to/index.md', + raw: './index.md', + relative: 'path/to/index.md', + absolute: '/path/to/index.md', }, { - raw: '/base/path/to/index.html', - relative: 'path/to/index.html', - absolute: '/base/path/to/index.html', + raw: '../index.md', + relative: 'path/index.md', + absolute: '/path/index.md', }, - ]) - }) + { + raw: '../foo/bar/index.md', + relative: 'path/foo/bar/index.md', + absolute: '/path/foo/bar/index.md', + }, + { + raw: 'readme.md', + relative: 'path/to/readme.md', + absolute: '/path/to/readme.md', + }, + { + raw: '../foo/bar/readme.md', + relative: 'path/foo/bar/readme.md', + absolute: '/path/foo/bar/readme.md', + }, + ].flatMap(({ raw, ...rest }) => [ + { raw, ...rest }, + { raw: `${raw}#hash`, ...rest }, + { raw: `${raw}?a=1&b=2`, ...rest }, + { raw: `${raw}#hash?a=1&b=2`, ...rest }, + { raw: `${raw}?a=1&b=2#hash`, ...rest }, + ]), + ) + }) + + it('should convert to absolute links correctly if the file path contains non-ASCII characters', () => { + const md = MarkdownIt({ html: true }).use(linksPlugin) + const env: MarkdownEnv = { + filePathRelative: '中/文/路径.md', + } + const encoded中 = encodeURI('中') + const encoded文 = encodeURI('文') + + const rendered = md.render(source, env) + + expect(rendered).toEqual( + [ + `foo1`, + `foo2`, + `bar1`, + `bar2`, + `foobar1`, + `foobar2`, + `index1`, + `index2`, + `index3`, + `index4`, + `readme1`, + `readme2`, + ] + .flatMap((item) => { + const link = /to="([^"]*)"/.exec(item)![1] + + return [ + item, + item.replace(link, `${link}#hash`), + item.replace(link, `${link}?a=1&b=2`), + item.replace(link, `${link}#hash?a=1&b=2`), + item.replace(link, `${link}?a=1&b=2#hash`), + ] + }) + .map((a) => `

${a}

`) + .join('\n') + '\n', + ) + + expect(env.links).toEqual( + [ + { + raw: 'foo.md', + relative: `${encoded中}/${encoded文}/foo.md`, + absolute: `/${encoded中}/${encoded文}/foo.md`, + }, + { + raw: './foo.md', + relative: `${encoded中}/${encoded文}/foo.md`, + absolute: `/${encoded中}/${encoded文}/foo.md`, + }, + { + raw: '../bar.md', + relative: `${encoded中}/bar.md`, + absolute: `/${encoded中}/bar.md`, + }, + { + raw: './../bar.md', + relative: `${encoded中}/bar.md`, + absolute: `/${encoded中}/bar.md`, + }, + { + raw: 'foo/bar.md', + relative: `${encoded中}/${encoded文}/foo/bar.md`, + absolute: `/${encoded中}/${encoded文}/foo/bar.md`, + }, + { + raw: '../foo/bar.md', + relative: `${encoded中}/foo/bar.md`, + absolute: `/${encoded中}/foo/bar.md`, + }, + { + raw: 'index.md', + relative: `${encoded中}/${encoded文}/index.md`, + absolute: `/${encoded中}/${encoded文}/index.md`, + }, + { + raw: './index.md', + relative: `${encoded中}/${encoded文}/index.md`, + absolute: `/${encoded中}/${encoded文}/index.md`, + }, + { + raw: '../index.md', + relative: `${encoded中}/index.md`, + absolute: `/${encoded中}/index.md`, + }, + { + raw: '../foo/bar/index.md', + relative: `${encoded中}/foo/bar/index.md`, + absolute: `/${encoded中}/foo/bar/index.md`, + }, + { + raw: 'readme.md', + relative: `${encoded中}/${encoded文}/readme.md`, + absolute: `/${encoded中}/${encoded文}/readme.md`, + }, + { + raw: '../foo/bar/readme.md', + relative: `${encoded中}/foo/bar/readme.md`, + absolute: `/${encoded中}/foo/bar/readme.md`, + }, + ].flatMap(({ raw, ...rest }) => [ + { raw, ...rest }, + { raw: `${raw}#hash`, ...rest }, + { raw: `${raw}?a=1&b=2`, ...rest }, + { raw: `${raw}#hash?a=1&b=2`, ...rest }, + { raw: `${raw}?a=1&b=2#hash`, ...rest }, + ]), + ) + }) - it('should render to tag correctly', () => { - const md = MarkdownIt({ html: true }).use(linksPlugin, { - internalTag: 'a', - }) - const env: MarkdownEnv = { - base: '/base/', - } - - const rendered = md.render(source, env) - - expect(rendered).toEqual( - [ - 'md', - 'md-with-redundant-base', - 'html', - ] - .map((a) => `

${a}

`) - .join('\n') + '\n', - ) - - expect(env.links).toEqual([ - { - raw: '/path/to/index.md', + it('should not conflict with base', () => { + const md = MarkdownIt({ html: true }).use(linksPlugin) + const env: MarkdownEnv = { + base: '/path/', + filePathRelative: 'path/to/file.md', + } + + const rendered = md.render(source, env) + + expect(rendered).toEqual( + [ + 'foo1', + 'foo2', + 'bar1', + 'bar2', + 'foobar1', + 'foobar2', + 'index1', + 'index2', + 'index3', + 'index4', + 'readme1', + 'readme2', + ] + .flatMap((item) => { + const link = /to="([^"]*)"/.exec(item)![1] + + return [ + item, + item.replace(link, `${link}#hash`), + item.replace(link, `${link}?a=1&b=2`), + item.replace(link, `${link}#hash?a=1&b=2`), + item.replace(link, `${link}?a=1&b=2#hash`), + ] + }) + .map((a) => `

${a}

`) + .join('\n') + '\n', + ) + + expect(env.links).toEqual( + [ + { + raw: 'foo.md', + relative: 'path/to/foo.md', + absolute: '/path/path/to/foo.md', + }, + { + raw: './foo.md', + relative: 'path/to/foo.md', + absolute: '/path/path/to/foo.md', + }, + { + raw: '../bar.md', + relative: 'path/bar.md', + absolute: '/path/path/bar.md', + }, + { + raw: './../bar.md', + relative: 'path/bar.md', + absolute: '/path/path/bar.md', + }, + { + raw: 'foo/bar.md', + relative: 'path/to/foo/bar.md', + absolute: '/path/path/to/foo/bar.md', + }, + { + raw: '../foo/bar.md', + relative: 'path/foo/bar.md', + absolute: '/path/path/foo/bar.md', + }, + { + raw: 'index.md', relative: 'path/to/index.md', - absolute: '/base/path/to/index.md', + absolute: '/path/path/to/index.md', }, { - raw: '/base/path/to/index.md', - relative: 'base/path/to/index.md', - absolute: '/base/base/path/to/index.md', + raw: './index.md', + relative: 'path/to/index.md', + absolute: '/path/path/to/index.md', }, { - raw: '/base/path/to/index.html', - relative: 'path/to/index.html', - absolute: '/base/path/to/index.html', + raw: '../index.md', + relative: 'path/index.md', + absolute: '/path/path/index.md', }, - ]) - }) + { + raw: '../foo/bar/index.md', + relative: 'path/foo/bar/index.md', + absolute: '/path/path/foo/bar/index.md', + }, + { + raw: 'readme.md', + relative: 'path/to/readme.md', + absolute: '/path/path/to/readme.md', + }, + { + raw: '../foo/bar/readme.md', + relative: 'path/foo/bar/readme.md', + absolute: '/path/path/foo/bar/readme.md', + }, + ].flatMap(({ raw, ...rest }) => [ + { raw, ...rest }, + { raw: `${raw}#hash`, ...rest }, + { raw: `${raw}?a=1&b=2`, ...rest }, + { raw: `${raw}#hash?a=1&b=2`, ...rest }, + { raw: `${raw}?a=1&b=2#hash`, ...rest }, + ]), + ) }) }) - describe('empty links', () => { - it('should render correctly', () => { - const md = MarkdownIt({ html: true }).use(linksPlugin) - const env: MarkdownEnv = {} + describe('absolute links', () => { + const source = [ + '[md](/path/to/index.md)', + '[md-with-redundant-base](/base/path/to/index.md)', + '[html](/base/path/to/index.html)', + ].join('\n\n') - const rendered = md.render('[empty]()', env) + it('should resolve to internal links correctly', () => { + const md = MarkdownIt({ html: true }).use(linksPlugin) + const env: MarkdownEnv = { + base: '/base/', + } + + const rendered = md.render(source, env) + + expect(rendered).toEqual( + [ + 'md', + 'md-with-redundant-base', + 'html', + ] + .map((a) => `

${a}

`) + .join('\n') + '\n', + ) + + expect(env.links).toEqual([ + { + raw: '/path/to/index.md', + relative: 'path/to/index.md', + absolute: '/base/path/to/index.md', + }, + { + raw: '/base/path/to/index.md', + relative: 'base/path/to/index.md', + absolute: '/base/base/path/to/index.md', + }, + { + raw: '/base/path/to/index.html', + relative: 'path/to/index.html', + absolute: '/base/path/to/index.html', + }, + ]) + }) - expect(rendered).toEqual('

empty

\n') - expect(env.links).toBeUndefined() + it('should render to tag correctly', () => { + const md = MarkdownIt({ html: true }).use(linksPlugin, { + internalTag: 'a', + }) + const env: MarkdownEnv = { + base: '/base/', + } + + const rendered = md.render(source, env) + + expect(rendered).toEqual( + [ + 'md', + 'md-with-redundant-base', + 'html', + ] + .map((a) => `

${a}

`) + .join('\n') + '\n', + ) + + expect(env.links).toEqual([ + { + raw: '/path/to/index.md', + relative: 'path/to/index.md', + absolute: '/base/path/to/index.md', + }, + { + raw: '/base/path/to/index.md', + relative: 'base/path/to/index.md', + absolute: '/base/base/path/to/index.md', + }, + { + raw: '/base/path/to/index.html', + relative: 'path/to/index.html', + absolute: '/base/path/to/index.html', + }, + ]) }) }) }) + +describe('empty links', () => { + it('should render correctly', () => { + const md = MarkdownIt({ html: true }).use(linksPlugin) + const env: MarkdownEnv = {} + + const rendered = md.render('[empty]()', env) + + expect(rendered).toEqual('

empty

\n') + expect(env.links).toBeUndefined() + }) +}) diff --git a/packages/markdown/tests/plugins/vPrePlugin.spec.ts b/packages/markdown/tests/plugins/vPrePlugin.spec.ts index 128a163cf5..97610966fe 100644 --- a/packages/markdown/tests/plugins/vPrePlugin.spec.ts +++ b/packages/markdown/tests/plugins/vPrePlugin.spec.ts @@ -4,42 +4,41 @@ import { vPrePlugin } from '../../src/index.js' const CODE_FENCE = '```' -describe('@vuepress/markdown > plugins > vPrePlugin', () => { - describe('plugin options', () => { - const source = `\ +describe('plugin options', () => { + const source = `\ ${CODE_FENCE}js const a = 1 ${CODE_FENCE} \`inline\` ` - it('should process code with default options', () => { - const md = MarkdownIt().use(vPrePlugin) + it('should process code with default options', () => { + const md = MarkdownIt().use(vPrePlugin) - expect(md.render(source)).toMatchSnapshot() - }) + expect(md.render(source)).toMatchSnapshot() + }) - it('should disable `block`', () => { - const md = MarkdownIt().use(vPrePlugin, { block: false }) + it('should disable `block`', () => { + const md = MarkdownIt().use(vPrePlugin, { block: false }) - expect(md.render(source)).toMatchSnapshot() - }) + expect(md.render(source)).toMatchSnapshot() + }) - it('should disable `inline`', () => { - const md = MarkdownIt().use(vPrePlugin, { inline: false }) + it('should disable `inline`', () => { + const md = MarkdownIt().use(vPrePlugin, { inline: false }) - expect(md.render(source)).toMatchSnapshot() - }) + expect(md.render(source)).toMatchSnapshot() + }) - it('should disable `block` and `inline`', () => { - const md = MarkdownIt().use(vPrePlugin, { block: false, inline: false }) + it('should disable `block` and `inline`', () => { + const md = MarkdownIt().use(vPrePlugin, { block: false, inline: false }) - expect(md.render(source)).toMatchSnapshot() - }) + expect(md.render(source)).toMatchSnapshot() }) +}) - describe(':v-pre / :no-v-pre', () => { - const source = `\ +describe(':v-pre / :no-v-pre', () => { + const source = `\ ${CODE_FENCE}js:v-pre const a = 1 ${CODE_FENCE} @@ -68,21 +67,21 @@ ${CODE_FENCE}js const a = 1 ${CODE_FENCE} ` - it('should work if `block` is enabled by default', () => { - const md = MarkdownIt().use(vPrePlugin) + it('should work if `block` is enabled by default', () => { + const md = MarkdownIt().use(vPrePlugin) - expect(md.render(source)).toMatchSnapshot() - }) + expect(md.render(source)).toMatchSnapshot() + }) - it('should work if `block` is disabled', () => { - const md = MarkdownIt().use(vPrePlugin, { block: false }) + it('should work if `block` is disabled', () => { + const md = MarkdownIt().use(vPrePlugin, { block: false }) - expect(md.render(source)).toMatchSnapshot() - }) + expect(md.render(source)).toMatchSnapshot() }) +}) - describe('syntax highlighting', () => { - const source = `\ +describe('syntax highlighting', () => { + const source = `\ ${CODE_FENCE}js:v-pre const a = 1 ${CODE_FENCE} @@ -111,26 +110,25 @@ ${CODE_FENCE}js const a = 1 ${CODE_FENCE} ` - it('should work highlighted code is wrapped with `
`', () => {
-      const highlight = vi.fn(
-        (code, lang) =>
-          `
highlighted code: ${code}, lang: ${lang}
`, - ) - - const md = MarkdownIt({ highlight }).use(vPrePlugin) - - expect(md.render(source)).toMatchSnapshot() - expect(highlight).toHaveBeenCalledTimes(7) - }) - - it('should work if highlighted code is not wrapped with `
`', () => {
-      const highlight = vi.fn(
-        (code, lang) => `highlighted code: ${code}, lang: ${lang}`,
-      )
-      const md = MarkdownIt({ highlight }).use(vPrePlugin)
-
-      expect(md.render(source)).toMatchSnapshot()
-      expect(highlight).toHaveBeenCalledTimes(7)
-    })
+  it('should work highlighted code is wrapped with `
`', () => {
+    const highlight = vi.fn(
+      (code, lang) =>
+        `
highlighted code: ${code}, lang: ${lang}
`, + ) + + const md = MarkdownIt({ highlight }).use(vPrePlugin) + + expect(md.render(source)).toMatchSnapshot() + expect(highlight).toHaveBeenCalledTimes(7) + }) + + it('should work if highlighted code is not wrapped with `
`', () => {
+    const highlight = vi.fn(
+      (code, lang) => `highlighted code: ${code}, lang: ${lang}`,
+    )
+    const md = MarkdownIt({ highlight }).use(vPrePlugin)
+
+    expect(md.render(source)).toMatchSnapshot()
+    expect(highlight).toHaveBeenCalledTimes(7)
   })
 })