From ef2f86148425920cbb92034f6364a0118f2d56bc Mon Sep 17 00:00:00 2001 From: yosuke ota Date: Wed, 23 Nov 2022 01:42:48 +0900 Subject: [PATCH 1/7] Chore: use vitepress instead of vuepress --- .eslintignore | 7 +- .gitignore | 5 +- docs/.vitepress/build-system/build.ts | 69 ++++++ docs/.vitepress/build-system/shim/globby.mjs | 2 + docs/.vitepress/build-system/shim/path.mjs | 38 +++ docs/.vitepress/build-system/src/eslint.mjs | 5 + .../build-system/src/process-shim.mjs | 10 + docs/.vitepress/config.ts | 220 ++++++++++++++++++ .../public/favicon.png | Bin docs/.vitepress/theme/Layout.vue | 21 ++ .../theme}/components/eslint-code-block.vue | 63 +++-- .../theme}/components/rules-table.vue | 4 +- docs/.vitepress/theme/index.ts | 30 +++ docs/.vitepress/vite-plugin.ts | 53 +++++ docs/.vuepress/config.js | 193 --------------- docs/.vuepress/enhanceApp.js | 26 --- docs/.vuepress/shim/eslint.js | 4 - docs/.vuepress/shim/globby.js | 1 - docs/.vuepress/shim/module.js | 11 - docs/.vuepress/styles/index.styl | 26 --- docs/developer-guide/{README.md => index.md} | 0 docs/{README.md => index.md} | 2 +- docs/rules/{README.md => index.md} | 0 docs/rules/prefer-true-attribute-shorthand.md | 4 +- docs/user-guide/{README.md => index.md} | 2 +- lib/utils/index.js | 3 +- package.json | 14 +- tools/lib/categories.js | 35 +-- tools/update-docs-rules-index.js | 2 +- tsconfig.json | 2 +- 30 files changed, 527 insertions(+), 325 deletions(-) create mode 100644 docs/.vitepress/build-system/build.ts create mode 100644 docs/.vitepress/build-system/shim/globby.mjs create mode 100644 docs/.vitepress/build-system/shim/path.mjs create mode 100644 docs/.vitepress/build-system/src/eslint.mjs create mode 100644 docs/.vitepress/build-system/src/process-shim.mjs create mode 100644 docs/.vitepress/config.ts rename docs/{.vuepress => .vitepress}/public/favicon.png (100%) create mode 100644 docs/.vitepress/theme/Layout.vue rename docs/{.vuepress => .vitepress/theme}/components/eslint-code-block.vue (78%) rename docs/{.vuepress => .vitepress/theme}/components/rules-table.vue (95%) create mode 100644 docs/.vitepress/theme/index.ts create mode 100644 docs/.vitepress/vite-plugin.ts delete mode 100644 docs/.vuepress/config.js delete mode 100644 docs/.vuepress/enhanceApp.js delete mode 100644 docs/.vuepress/shim/eslint.js delete mode 100644 docs/.vuepress/shim/globby.js delete mode 100644 docs/.vuepress/shim/module.js delete mode 100644 docs/.vuepress/styles/index.styl rename docs/developer-guide/{README.md => index.md} (100%) rename docs/{README.md => index.md} (88%) rename docs/rules/{README.md => index.md} (100%) rename docs/user-guide/{README.md => index.md} (99%) diff --git a/.eslintignore b/.eslintignore index 1905aa4a8..a0c203ada 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,5 +4,8 @@ /tests/fixtures /tests/integrations/eslint-plugin-import -!.vuepress -/docs/.vuepress/dist +!.vitepress +/docs/.vitepress/dist +/docs/.vitepress/build-system/shim/eslint.mjs +/docs/.vitepress/build-system/shim/assert.mjs +/docs/.vitepress/.temp diff --git a/.gitignore b/.gitignore index e1401b951..06fb2db3b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,8 @@ /test.* yarn.lock yarn-error.log -docs/.vuepress/dist +/docs/.vitepress/dist +/docs/.vitepress/build-system/shim/eslint.mjs +/docs/.vitepress/build-system/shim/assert.mjs +/docs/.vitepress/.temp typings/eslint/lib/rules diff --git a/docs/.vitepress/build-system/build.ts b/docs/.vitepress/build-system/build.ts new file mode 100644 index 000000000..db4a80ad3 --- /dev/null +++ b/docs/.vitepress/build-system/build.ts @@ -0,0 +1,69 @@ +/** + * Pre-build cjs packages that cannot be bundled well. + */ +import esbuild from 'esbuild' +import path from 'path' +import fs from 'fs' +import { fileURLToPath } from 'url' + +const dirname = path.dirname( + fileURLToPath( + // @ts-expect-error -- Cannot change `module` option + import.meta.url + ) +) + +build( + path.join(dirname, './src/eslint.mjs'), + path.join(dirname, './shim/eslint.mjs'), + ['path', 'assert', 'util'] +) +build( + path.join(dirname, '../../../node_modules/assert'), + path.join(dirname, './shim/assert.mjs'), + ['path'] +) + +/** build */ +function build(input: string, out: string, injects: string[] = []) { + // eslint-disable-next-line no-console -- ignore + console.log(`build@ ${input}`) + let code = bundle(input, injects) + code = transform(code, injects) + fs.mkdirSync(path.dirname(out), { recursive: true }) + fs.writeFileSync(out, code, 'utf8') +} + +/** bundle */ +function bundle(entryPoint: string, externals: string[]) { + const result = esbuild.buildSync({ + entryPoints: [entryPoint], + format: 'esm', + bundle: true, + external: externals, + write: false, + inject: [path.join(dirname, './src/process-shim.mjs')] + }) + + return `${result.outputFiles[0].text}` +} + +/** transform code */ +function transform(code: string, injects: string[]) { + const newCode = code.replace(/"[a-z]+" = "[a-z]+";/u, '') + return ` +${injects + .map( + (inject) => + `import $inject_${inject.replace(/-/gu, '_')}$ from '${inject}';` + ) + .join('\n')} +const $_injects_$ = {${injects + .map((inject) => `${inject.replace(/-/gu, '_')}:$inject_${inject}$`) + .join(',\n')}}; +function require(module, ...args) { + return $_injects_$[module] || {} +} +${newCode} +` +} diff --git a/docs/.vitepress/build-system/shim/globby.mjs b/docs/.vitepress/build-system/shim/globby.mjs new file mode 100644 index 000000000..57d1de9f1 --- /dev/null +++ b/docs/.vitepress/build-system/shim/globby.mjs @@ -0,0 +1,2 @@ +export {} +export default {} diff --git a/docs/.vitepress/build-system/shim/path.mjs b/docs/.vitepress/build-system/shim/path.mjs new file mode 100644 index 000000000..544792b00 --- /dev/null +++ b/docs/.vitepress/build-system/shim/path.mjs @@ -0,0 +1,38 @@ +// @ts-nocheck +export const sep = '/' +export function basename(path, ext) { + const b = (/[^\/]*$/u.exec(path) || [''])[0] + return ext && b.endsWith(ext) ? b.slice(0, -ext.length) : b +} +export function extname(path) { + return (/[^.\/]*$/u.exec(path) || [''])[0] +} +export function isAbsolute() { + return false +} +export function join(...args) { + return args.length > 0 ? normalize(args.join('/')) : '.' +} + +function normalize(path) { + const result = [] + for (const part of path.replace(/\/+/gu, '/').split('/')) { + if (part === '..') { + if (result[0] && result[0] !== '..' && result[0] !== '.') result.shift() + } else if (part === '.' && result.length > 0) { + // noop + } else { + result.unshift(part) + } + } + return result.reverse().join('/') +} +const posix = { + sep, + basename, + extname, + isAbsolute, + join +} +posix.posix = posix +export default posix diff --git a/docs/.vitepress/build-system/src/eslint.mjs b/docs/.vitepress/build-system/src/eslint.mjs new file mode 100644 index 000000000..6604e0bb4 --- /dev/null +++ b/docs/.vitepress/build-system/src/eslint.mjs @@ -0,0 +1,5 @@ +// @ts-nocheck +import * as all from '../../../../node_modules/eslint/lib/linter/linter.js' +const Linter = all.Linter +export { Linter } +export default { Linter } diff --git a/docs/.vitepress/build-system/src/process-shim.mjs b/docs/.vitepress/build-system/src/process-shim.mjs new file mode 100644 index 000000000..6b75bf56e --- /dev/null +++ b/docs/.vitepress/build-system/src/process-shim.mjs @@ -0,0 +1,10 @@ +/* globals window */ +// @ts-nocheck +export const process = { + env: {}, + cwd: () => '', + stdout: {} +} +if (typeof window !== 'undefined') { + window.process = process +} diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts new file mode 100644 index 000000000..57197d101 --- /dev/null +++ b/docs/.vitepress/config.ts @@ -0,0 +1,220 @@ +import type { DefaultTheme } from 'vitepress' +import { defineConfig } from 'vitepress' +import { BUNDLED_LANGUAGES } from 'shiki' +import path from 'path' +import { fileURLToPath } from 'url' +import rules from '../../tools/lib/rules' +import { viteCommonjs, vitePluginRequireResolve } from './vite-plugin' + +// Pre-build cjs packages that cannot be bundled well. +import './build-system/build' + +const dirname = path.dirname( + fileURLToPath( + // @ts-expect-error -- Cannot change `module` option + import.meta.url + ) +) + +// Include `json5` as alias for jsonc +const jsonc = BUNDLED_LANGUAGES.find((lang) => lang.id === 'jsonc') +if (jsonc) jsonc.aliases = [...(jsonc?.aliases ?? []), 'json5'] + +const uncategorizedRules = rules.filter( + (rule) => + !rule.meta.docs.categories && + !rule.meta.docs.extensionRule && + !rule.meta.deprecated +) +const uncategorizedExtensionRule = rules.filter( + (rule) => + !rule.meta.docs.categories && + rule.meta.docs.extensionRule && + !rule.meta.deprecated +) +const deprecatedRules = rules.filter((rule) => rule.meta.deprecated) + +const sidebarCategories = [ + { title: 'Base Rules', categoryIds: ['base'] }, + { + title: 'Priority A: Essential', + categoryIds: ['vue3-essential', 'essential'] + }, + { + title: 'Priority A: Essential for Vue.js 3.x', + categoryIds: ['vue3-essential'] + }, + { title: 'Priority A: Essential for Vue.js 2.x', categoryIds: ['essential'] }, + { + title: 'Priority B: Strongly Recommended', + categoryIds: ['vue3-strongly-recommended', 'strongly-recommended'] + }, + { + title: 'Priority B: Strongly Recommended for Vue.js 3.x', + categoryIds: ['vue3-strongly-recommended'] + }, + { + title: 'Priority B: Strongly Recommended for Vue.js 2.x', + categoryIds: ['strongly-recommended'] + }, + { + title: 'Priority C: Recommended', + categoryIds: ['vue3-recommended', 'recommended'] + }, + { + title: 'Priority C: Recommended for Vue.js 3.x', + categoryIds: ['vue3-recommended'] + }, + { + title: 'Priority C: Recommended for Vue.js 2.x', + categoryIds: ['recommended'] + } +] + +const categorizedRules: DefaultTheme.SidebarGroup[] = [] +for (const { title, categoryIds } of sidebarCategories) { + const categoryRules = rules + .filter((rule) => rule.meta.docs.categories && !rule.meta.deprecated) + .filter((rule) => + categoryIds.every((categoryId) => + rule.meta.docs.categories.includes(categoryId) + ) + ) + const children: DefaultTheme.SidebarItem[] = categoryRules + .filter(({ ruleId }) => { + const exists = categorizedRules.some(({ items }) => + items.some(({ text: alreadyRuleId }) => alreadyRuleId === ruleId) + ) + return !exists + }) + .map(({ ruleId, name }) => { + return { + text: ruleId, + link: `/rules/${name}` + } + }) + + if (children.length === 0) { + continue + } + categorizedRules.push({ + text: title, + collapsible: false, + items: children + }) +} + +const extraCategories: DefaultTheme.SidebarGroup[] = [] +if (uncategorizedRules.length > 0) { + extraCategories.push({ + text: 'Uncategorized', + collapsible: false, + items: uncategorizedRules.map(({ ruleId, name }) => ({ + text: ruleId, + link: `/rules/${name}` + })) + }) +} +if (uncategorizedExtensionRule.length > 0) { + extraCategories.push({ + text: 'Extension Rules', + collapsible: false, + items: uncategorizedExtensionRule.map(({ ruleId, name }) => ({ + text: ruleId, + link: `/rules/${name}` + })) + }) +} +if (deprecatedRules.length > 0) { + extraCategories.push({ + text: 'Deprecated', + collapsible: false, + items: deprecatedRules.map(({ ruleId, name }) => ({ + text: ruleId, + link: `/rules/${name}` + })) + }) +} + +export default defineConfig({ + base: '/', + title: 'eslint-plugin-vue', + description: 'Official ESLint plugin for Vue.js', + head: [['link', { rel: 'icon', href: '/favicon.png' }]], + + vite: { + publicDir: path.resolve(dirname, './public'), + plugins: [vitePluginRequireResolve(), viteCommonjs()], + resolve: { + alias: { + eslint: path.join(dirname, './build-system/shim/eslint.mjs'), + assert: path.join(dirname, './build-system/shim/assert.mjs'), + path: path.join(dirname, './build-system/shim/path.mjs'), + + tslib: path.join(dirname, '../../node_modules/tslib/tslib.es6.js'), + globby: path.join(dirname, './build-system/shim/globby.mjs') + } + }, + define: { + 'process.env.NODE_DEBUG': 'false', + 'require.cache': '{}' + } + }, + + lastUpdated: true, + themeConfig: { + editLink: { + pattern: + 'https://github.com/vuejs/eslint-plugin-vue/edit/master/docs/:path' + }, + socialLinks: [ + { + icon: 'github', + link: 'https://github.com/vuejs/eslint-plugin-vue' + } + ], + + nav: [ + { text: 'User Guide', link: '/user-guide/' }, + { text: 'Developer Guide', link: '/developer-guide/' }, + { text: 'Rules', link: '/rules/' }, + { + text: 'Demo', + link: 'https://ota-meshi.github.io/eslint-plugin-vue-demo/' + } + ], + + sidebar: { + '/rules/': [ + { + text: 'Rules', + items: [{ text: 'Available Rules', link: '/rules/' }] + }, + + // Rules in each category. + ...categorizedRules, + + // Rules in no category. + ...extraCategories + ], + + '/': [ + { + text: 'Guide', + items: [ + { text: 'Introduction', link: '/' }, + { text: 'User Guide', link: '/user-guide/' }, + { text: 'Developer Guide', link: '/developer-guide/' }, + { text: 'Rules', link: '/rules/' } + ] + } + ] + }, + + algolia: { + appId: '2L4MGZSULB', + apiKey: 'fdf57932b27a6c230d01a890492ab76d', + indexName: 'eslint-plugin-vue' + } + } +}) diff --git a/docs/.vuepress/public/favicon.png b/docs/.vitepress/public/favicon.png similarity index 100% rename from docs/.vuepress/public/favicon.png rename to docs/.vitepress/public/favicon.png diff --git a/docs/.vitepress/theme/Layout.vue b/docs/.vitepress/theme/Layout.vue new file mode 100644 index 000000000..3be00694b --- /dev/null +++ b/docs/.vitepress/theme/Layout.vue @@ -0,0 +1,21 @@ + + + + + diff --git a/docs/.vuepress/components/eslint-code-block.vue b/docs/.vitepress/theme/components/eslint-code-block.vue similarity index 78% rename from docs/.vuepress/components/eslint-code-block.vue rename to docs/.vitepress/theme/components/eslint-code-block.vue index b95e0d070..77d4fd7cf 100644 --- a/docs/.vuepress/components/eslint-code-block.vue +++ b/docs/.vitepress/theme/components/eslint-code-block.vue @@ -3,7 +3,7 @@ diff --git a/docs/.vuepress/components/rules-table.vue b/docs/.vitepress/theme/components/rules-table.vue similarity index 95% rename from docs/.vuepress/components/rules-table.vue rename to docs/.vitepress/theme/components/rules-table.vue index 29d31c4c6..c517d4591 100644 --- a/docs/.vuepress/components/rules-table.vue +++ b/docs/.vitepress/theme/components/rules-table.vue @@ -77,10 +77,10 @@ export default {