From 55b4f2d49cd11c72eedccf15e160233c3434bffd Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Mon, 1 Apr 2024 00:20:01 +0900 Subject: [PATCH] Use vitepress & twoslash --- .eslintignore | 5 +- .gitignore | 6 + .stylelintignore | 5 +- README.md | 7 +- docs/.vitepress/config.mjs | 140 ++++++++ docs/.vitepress/stylelint.config.js | 11 + docs/.vitepress/theme/index.ts | 13 + docs/.vitepress/theme/style.css | 13 + .../.vitepress/twoslash-stylelint/index.d.mts | 33 ++ docs/.vitepress/twoslash-stylelint/index.mjs | 81 +++++ .../twoslash-stylelint/stylelint-worker.mjs | 17 + docs/.vuepress/.eslintrc.js | 12 - docs/.vuepress/components/playground.vue | 282 ---------------- .../playground/components/JsonEditor.vue | 301 ------------------ .../playground/state/deserialize.js | 29 -- .../components/playground/state/index.js | 3 - .../components/playground/state/serialize.js | 26 -- .../components/stylelint-code-block.vue | 121 ------- docs/.vuepress/components/stylelint4b.js | 78 ----- docs/.vuepress/config.js | 107 ------- docs/.vuepress/enhanceApp.js | 15 - docs/.vuepress/shim/empty.js | 1 - docs/.vuepress/shim/glob.js | 1 - docs/.vuepress/shim/sax.js | 1 - docs/.vuepress/styles/index.styl | 56 ---- docs/{README.md => index.md} | 7 +- docs/playground/README.md | 13 - docs/rules/at-extend-style.md | 10 +- docs/rules/at-rule-no-unknown.md | 5 +- docs/rules/declaration-colon.md | 10 +- docs/rules/hash-object-property-comma.md | 15 +- docs/rules/media-feature-colon.md | 10 +- docs/rules/no-at-require.md | 5 +- docs/rules/pythonic.md | 20 +- docs/rules/selector-list-comma.md | 10 +- docs/rules/semicolon.md | 10 +- ...e-line-comment-double-slash-space-after.md | 10 +- docs/rules/single-line-comment-no-empty.md | 5 +- docs/rules/single-line-comment.md | 10 +- lib/rules/semicolon.js | 11 +- package.json | 12 +- scripts/update-readme.js | 6 +- 42 files changed, 370 insertions(+), 1163 deletions(-) create mode 100644 docs/.vitepress/config.mjs create mode 100644 docs/.vitepress/stylelint.config.js create mode 100644 docs/.vitepress/theme/index.ts create mode 100644 docs/.vitepress/theme/style.css create mode 100644 docs/.vitepress/twoslash-stylelint/index.d.mts create mode 100644 docs/.vitepress/twoslash-stylelint/index.mjs create mode 100644 docs/.vitepress/twoslash-stylelint/stylelint-worker.mjs delete mode 100644 docs/.vuepress/.eslintrc.js delete mode 100644 docs/.vuepress/components/playground.vue delete mode 100644 docs/.vuepress/components/playground/components/JsonEditor.vue delete mode 100644 docs/.vuepress/components/playground/state/deserialize.js delete mode 100644 docs/.vuepress/components/playground/state/index.js delete mode 100644 docs/.vuepress/components/playground/state/serialize.js delete mode 100644 docs/.vuepress/components/stylelint-code-block.vue delete mode 100644 docs/.vuepress/components/stylelint4b.js delete mode 100644 docs/.vuepress/config.js delete mode 100644 docs/.vuepress/enhanceApp.js delete mode 100644 docs/.vuepress/shim/empty.js delete mode 100644 docs/.vuepress/shim/glob.js delete mode 100644 docs/.vuepress/shim/sax.js delete mode 100644 docs/.vuepress/styles/index.styl rename docs/{README.md => index.md} (93%) delete mode 100644 docs/playground/README.md diff --git a/.eslintignore b/.eslintignore index 34682cd..67c4044 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,5 +3,6 @@ node_modules /test-file /tests/fixtures -!/docs/.vuepress -/docs/.vuepress/dist +!/docs/.vitepress +/docs/.vitepress/dist +/docs/.vitepress/cache diff --git a/.gitignore b/.gitignore index 39a709b..5854d46 100644 --- a/.gitignore +++ b/.gitignore @@ -88,6 +88,10 @@ dist # vuepress build output .vuepress/dist +# vitepress build output +/docs/.vitepress/dist +/docs/.vitepress/cache + # Serverless directories .serverless/ @@ -108,3 +112,5 @@ dist /index.html /alias-package + +!docs/.vitepress/twoslash-stylelint/dist \ No newline at end of file diff --git a/.stylelintignore b/.stylelintignore index ec582e3..2a692e8 100644 --- a/.stylelintignore +++ b/.stylelintignore @@ -1,5 +1,6 @@ -!/docs/.vuepress -/docs/.vuepress/dist +!/docs/.vitepress +/docs/.vitepress/dist +/docs/.vitepress/cache /.nyc_output /coverage node_modules diff --git a/README.md b/README.md index a5e37a9..964d058 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

stylelint-stylus

-

Stylelint plugin for Stylus. +

Stylelint plugin for Stylus.

This plugin is still in an experimental state

@@ -34,7 +34,7 @@ This plugin allows us to check the [Stylus] with [Stylelint]. [Stylelint editor integrations](https://stylelint.io/user-guide/integrations/editor) are useful to check your code in real-time. -You can check on the [Online DEMO](https://stylus.github.io/stylelint-stylus/playground/). +You can check on the [Online DEMO](https://stylelint.io/demo/#N4Igxg9gJgpiBcID0SAEAVATgT1QZQBdsAbAVwGcBCAHQDsAjaXYO1VAMwloPlQEYALAAcAHkj4A6AKyoAEjGIA3GAQCWYAIYAaVBsyqNxHeQ21yAWnIx97ANytUAYmIQA5hFQtabNo0yxMc0wNKFUKXilRe29UAF86eNo6FFQAMWIYEVV6DNRybG4NETpGKGwHTm5+YTFJGXklFXVtXX1DY1MLKxs6B3pSAgIuPoGh2gl+weGY1VohAYBtIiEYAF5qEEmxjYBdB1n5giXsFfWQclJ6AFtVAl2HXwh-ayCQsPJUSOKk2hSAWVUWTMJSeAVeoQoAApFIYAJQOcwAdxg9AA1rdzH4wcEIeReDDiAirhAAF6Y0EvHHvfGGPoUwJU8KoAkOEqjLieOnPBlvKFfWHRRIgLQgdiqDIAOQ0VzgiEy0qEGQk5CIxGF4C4YtcCBAXjYG0yBBgtCg5A2vAWD1QGxVJAUswIllVFCQKtMUD0UA2Dj2tFi6sgtC1qSeVw0BB1ACtyFx1bAhOQdXrredVfbuOaU8RwzAVRstKzU3biA6nSQKJmNtmjXmQAkQLEgA). ## :cd: Installation @@ -207,9 +207,8 @@ These rules relate to style guidelines. ## License -See the [LICENSE] file for license rights and limitations (MIT). +See the [LICENSE](./LICENSE) file for license rights and limitations (MIT). -[license]: ./LICENSE [stylelint]: https://stylelint.io/ [stylus]: https://stylus-lang.com/ [vscode extension]: https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint diff --git a/docs/.vitepress/config.mjs b/docs/.vitepress/config.mjs new file mode 100644 index 0000000..14d4f5b --- /dev/null +++ b/docs/.vitepress/config.mjs @@ -0,0 +1,140 @@ +import { defineConfig } from "vitepress" +import path from "path" +import { fileURLToPath } from "url" +import { transformerTwoslash } from "@shikijs/vitepress-twoslash" +import { createTwoslasher as createTwoslasherStylelint } from "./twoslash-stylelint/index.mjs" + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +function ruleToSidebarItem({ ruleName, fileName }) { + return { + text: ruleName, + link: `/rules/${fileName}`, + } +} + +export default async () => { + const categoriesPath = path.join(dirname, "../../scripts/lib/categories.js") + const { categories, uncategorizedRules, deprecatedRules } = await import( + categoriesPath + ).then((m) => m.default || m) + + const extraCategories = [] + if (uncategorizedRules.length > 0) { + extraCategories.push({ + text: "Uncategorized", + collapsed: false, + items: uncategorizedRules.map(ruleToSidebarItem), + }) + } + if (deprecatedRules.length > 0) { + extraCategories.push({ + text: "Deprecated", + collapsed: false, + items: deprecatedRules.map(ruleToSidebarItem), + }) + } + + const configExtractor = /\/\*\s*stylelint rules config:(.*?)\*\//u + + const pluginPath = path.join(dirname, "../../lib/index.js") + return defineConfig({ + base: "/stylelint-stylus/", + title: "stylelint-stylus", + outDir: path.join(dirname, "./dist/stylelint-stylus"), + description: "Stylelint plugin for Stylus", + head: [], + lastUpdated: true, + markdown: { + codeTransformers: [ + transformerTwoslash({ + explicitTrigger: false, // Required for v-menu to work. + langs: ["stylus", "styl"], + filter(lang, code) { + if ( + lang.startsWith("stylus") || + lang.startsWith("styl") + ) { + return configExtractor.test(code) + } + return false + }, + errorRendering: "hover", + twoslasher: (code, ...args) => { + const config = configExtractor.exec(code)[1] + + const twoslasher = createTwoslasherStylelint({ + stylelintConfig: { + plugins: [pluginPath], + extends: ["stylelint-config-html"], + overrides: [ + { + files: [ + "*.stylus", + "*.styl", + "**/*.stylus", + "**/*.styl", + ], + customSyntax: "postcss-styl", + rules: JSON.parse(config), + }, + ], + }, + }) + return twoslasher(code, ...args) + }, + }), + ], + }, + themeConfig: { + siteTitle: "stylelint-stylus", + search: { + provider: "local", + options: { + detailedView: true, + }, + }, + editLink: { + pattern: + "https://github.com/stylus/stylelint-stylus/edit/main/docs/:path", + }, + nav: [ + { text: "User Guide", link: "/" }, + { + text: "Playground", + link: "https://stylelint.io/demo/#N4Igxg9gJgpiBcID0SAEAVATgT1QZQBdsAbAVwGcBCAHQDsAjaXYO1VAMwloPlQEYALAAcAHkj4A6AKyoAEjGIA3GAQCWYAIYAaVBsyqNxHeQ21yAWnIx97ANytUAYmIQA5hFQtabNo0yxMc0wNKFUKXilRe29UAF86eNo6FFQAMWIYEVV6DNRybG4NETpGKGwHTm5+YTFJGXklFXVtXX1DY1MLKxs6B3pSAgIuPoGh2gl+weGY1VohAYBtIiEYAF5qEEmxjYBdB1n5giXsFfWQclJ6AFtVAl2HXwh-ayCQsPJUSOKk2hSAWVUWTMJSeAVeoQoAApFIYAJQOcwAdxg9AA1rdzH4wcEIeReDDiAirhAAF6Y0EvHHvfGGPoUwJU8KoAkOEqjLieOnPBlvKFfWHRRIgLQgdiqDIAOQ0VzgiEy0qEGQk5CIxGF4C4YtcCBAXjYG0yBBgtCg5A2vAWD1QGxVJAUswIllVFCQKtMUD0UA2Dj2tFi6sgtC1qSeVw0BB1ACtyFx1bAhOQdXrredVfbuOaU8RwzAVRstKzU3biA6nSQKJmNtmjXmQAkQLEgA", + }, + ], + socialLinks: [ + { + icon: "github", + link: "https://github.com/stylus/stylelint-stylus", + }, + ], + sidebar: { + "/": [ + { + text: "Guide", + items: [{ text: "User Guide", link: "/" }], + }, + { + text: "Rules", + items: [ + ...categories + .map(({ title, rules: catRules }) => ({ + text: title.replace(/ \(.+?\)/u, ""), + collapsed: false, + items: catRules.map(ruleToSidebarItem), + })) + .filter((menu) => Boolean(menu.items.length)), + + // Rules in no category. + ...extraCategories, + ], + }, + ], + }, + }, + }) +} diff --git a/docs/.vitepress/stylelint.config.js b/docs/.vitepress/stylelint.config.js new file mode 100644 index 0000000..3a9e7a0 --- /dev/null +++ b/docs/.vitepress/stylelint.config.js @@ -0,0 +1,11 @@ +module.exports = { + extends: ["stylelint-config-standard-vue"], + rules: { + "no-descending-specificity": null, + "selector-class-pattern": null, + "value-keyword-case": null, + + // Conflict with Prettier + // indentation: null, + }, +}; diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts new file mode 100644 index 0000000..3ece50d --- /dev/null +++ b/docs/.vitepress/theme/index.ts @@ -0,0 +1,13 @@ +import type { Theme, EnhanceAppContext } from "vitepress"; +import DefaultTheme from "vitepress/theme"; +import TwoslashFloatingVue from "@shikijs/vitepress-twoslash/client"; +import "@shikijs/vitepress-twoslash/style.css"; +import "./style.css"; + +const theme: Theme = { + extends: DefaultTheme, + enhanceApp({ app }: EnhanceAppContext) { + app.use(TwoslashFloatingVue as never); + }, +}; +export default theme; diff --git a/docs/.vitepress/theme/style.css b/docs/.vitepress/theme/style.css new file mode 100644 index 0000000..5416ca9 --- /dev/null +++ b/docs/.vitepress/theme/style.css @@ -0,0 +1,13 @@ +a > img { + display: inline-block; +} + +a.title { + white-space: pre-wrap; +} + +.twoslash-error-hover > * { + min-width: 4px; + min-height: 16px; + display: inline-block; +} diff --git a/docs/.vitepress/twoslash-stylelint/index.d.mts b/docs/.vitepress/twoslash-stylelint/index.d.mts new file mode 100644 index 0000000..23c4889 --- /dev/null +++ b/docs/.vitepress/twoslash-stylelint/index.d.mts @@ -0,0 +1,33 @@ +import * as stylelint from 'stylelint'; +import { TwoslashGenericFunction } from 'twoslash-protocol'; + +interface CreateTwoslashStylelintOptions { + /** + * Flat configs for Stylelint + */ + stylelintConfig: stylelint.Config; + /** + * Custom code transform before sending to Stylelint for verification + * + * This does not affect the code rendering + */ + stylelintCodePreprocess?: (code: string) => string; + /** + * The current working directory for Stylelint + */ + cwd?: string; + /** + * Include the parsed docs in the result + * + * @default true + */ + includeDocs?: boolean; + /** + * Merge error messages that has same range + * @default true + */ + mergeMessages?: boolean; +} +declare function createTwoslasher(options: CreateTwoslashStylelintOptions): TwoslashGenericFunction; + +export { type CreateTwoslashStylelintOptions, createTwoslasher }; diff --git a/docs/.vitepress/twoslash-stylelint/index.mjs b/docs/.vitepress/twoslash-stylelint/index.mjs new file mode 100644 index 0000000..730dbf3 --- /dev/null +++ b/docs/.vitepress/twoslash-stylelint/index.mjs @@ -0,0 +1,81 @@ +import { fileURLToPath } from "node:url" +import * as path from "node:path" +import { + createPositionConverter, + resolveNodePositions, +} from "twoslash-protocol" +import { createSyncFn } from "synckit" + +function createTwoslasher(options) { + const { includeDocs = true, mergeMessages = true } = options + const workerPath = path.join( + fileURLToPath(import.meta.url), + "../stylelint-worker.mjs", + ) + const lint = createSyncFn(workerPath) + return (code, file) => { + const filename = file?.includes(".") ? file : `index.${file ?? "css"}` + const linterResult = lint({ + config: options.stylelintConfig, + codeFilename: filename, + code: options.stylelintCodePreprocess?.(code) || code, + }) + const result = linterResult.results[0] + const pc = createPositionConverter(code) + const raws = result.warnings.map((message) => { + const start = pc.posToIndex(message.line - 1, message.column - 1) + const end = + message.endLine != null && message.endColumn != null + ? pc.posToIndex(message.endLine - 1, message.endColumn - 1) + : start + 1 + let text = message.text + if (message.rule) { + const link = + includeDocs && + linterResult.ruleMetadata?.[message.rule]?.url + text += link + ? ` ([${message.rule}](${link}))` + : ` (${message.rule})` + } + return { + type: "error", + id: message.rule || "", + code: 0, + text, + start, + length: end - start, + level: message.severity, + filename, + } + }) + let merged = [] + if (mergeMessages) { + for (const current of raws) { + const existing = merged.find( + (r) => + r.start === current.start && + r.length === current.length, + ) + if (existing) { + existing.text += ` + +${current.text}` + continue + } + merged.push(current) + } + } else { + merged = raws + } + const nodes = resolveNodePositions(merged, code).filter( + (i) => i.line < pc.lines.length, + ) + const results = { + code, + nodes, + } + return results + } +} + +export { createTwoslasher } diff --git a/docs/.vitepress/twoslash-stylelint/stylelint-worker.mjs b/docs/.vitepress/twoslash-stylelint/stylelint-worker.mjs new file mode 100644 index 0000000..9dd3658 --- /dev/null +++ b/docs/.vitepress/twoslash-stylelint/stylelint-worker.mjs @@ -0,0 +1,17 @@ +import { runAsWorker } from "synckit" + +runAsWorker(lint) + +async function lint(options) { + const stylelint = await import("stylelint").then((m) => m.default || m) + const result = await stylelint.lint(options) + // Returns only cloneable values for subsequent use. + return { + results: result.results.map((r) => { + return { + warnings: r.warnings, + } + }), + ruleMetadata: result.ruleMetadata, + } +} diff --git a/docs/.vuepress/.eslintrc.js b/docs/.vuepress/.eslintrc.js deleted file mode 100644 index 854d8cc..0000000 --- a/docs/.vuepress/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - parserOptions: { - sourceType: "module", - }, - globals: { - window: true, - require: true, - }, - rules: { - "@mysticatea/node/no-unsupported-features/es-syntax": "off", - }, -} diff --git a/docs/.vuepress/components/playground.vue b/docs/.vuepress/components/playground.vue deleted file mode 100644 index b1d3f91..0000000 --- a/docs/.vuepress/components/playground.vue +++ /dev/null @@ -1,282 +0,0 @@ - - - - diff --git a/docs/.vuepress/components/playground/components/JsonEditor.vue b/docs/.vuepress/components/playground/components/JsonEditor.vue deleted file mode 100644 index 72ece75..0000000 --- a/docs/.vuepress/components/playground/components/JsonEditor.vue +++ /dev/null @@ -1,301 +0,0 @@ - - - - - diff --git a/docs/.vuepress/components/playground/state/deserialize.js b/docs/.vuepress/components/playground/state/deserialize.js deleted file mode 100644 index 3c5cc7b..0000000 --- a/docs/.vuepress/components/playground/state/deserialize.js +++ /dev/null @@ -1,29 +0,0 @@ -/* eslint node/no-unsupported-features/es-syntax: 0, node/no-missing-import: 0 -- ignore */ -import pako from "pako" - -/** - * Deserialize a given serialized string then update this object. - * @param {string} serializedString A serialized string. - * @returns {object} The deserialized state. - */ -export function deserializeState(serializedString) { - if (serializedString === "") { - return {} - } - - try { - const compressedString = window.atob(serializedString) - const uint8Arr = pako.inflate( - Uint8Array.from(compressedString, (c) => c.charCodeAt(0)), - ) - const jsonText = new TextDecoder().decode(uint8Arr) - const json = JSON.parse(jsonText) - - return json || {} - } catch (error) { - // eslint-disable-next-line no-console -- ignore - console.error(error) - } - - return {} -} diff --git a/docs/.vuepress/components/playground/state/index.js b/docs/.vuepress/components/playground/state/index.js deleted file mode 100644 index 5921879..0000000 --- a/docs/.vuepress/components/playground/state/index.js +++ /dev/null @@ -1,3 +0,0 @@ -/* eslint node/no-unsupported-features/es-syntax: 0 -- ignore */ -export * from "./deserialize" -export * from "./serialize" diff --git a/docs/.vuepress/components/playground/state/serialize.js b/docs/.vuepress/components/playground/state/serialize.js deleted file mode 100644 index 4fe917f..0000000 --- a/docs/.vuepress/components/playground/state/serialize.js +++ /dev/null @@ -1,26 +0,0 @@ -/* eslint node/no-unsupported-features/es-syntax: 0, node/no-missing-import: 0 -- ignore */ -import pako from "pako" - -/** - * Serialize a given state as a base64 string. - * @param {State} state The state to serialize. - * @returns {string} The serialized string. - */ -export function serializeState(saveData) { - const jsonString = JSON.stringify(saveData) - const uint8Arr = new TextEncoder().encode(jsonString) - const compressedString = String.fromCharCode(...pako.deflate(uint8Arr)) - const base64 = - (typeof window !== "undefined" && window.btoa(compressedString)) || - compressedString - - // eslint-disable-next-line no-console -- ignore - console.log( - `The compress rate of serialized string: ${( - (100 * base64.length) / - jsonString.length - ).toFixed(1)}% (${jsonString.length}B → ${base64.length}B)`, - ) - - return base64 -} diff --git a/docs/.vuepress/components/stylelint-code-block.vue b/docs/.vuepress/components/stylelint-code-block.vue deleted file mode 100644 index 9b52ad7..0000000 --- a/docs/.vuepress/components/stylelint-code-block.vue +++ /dev/null @@ -1,121 +0,0 @@ - - - - diff --git a/docs/.vuepress/components/stylelint4b.js b/docs/.vuepress/components/stylelint4b.js deleted file mode 100644 index 6606301..0000000 --- a/docs/.vuepress/components/stylelint4b.js +++ /dev/null @@ -1,78 +0,0 @@ -/* eslint node/no-unsupported-features/es-syntax: 0 -- ignore */ -export async function loadStylelint4b() { - const stylelint4b = import("stylelint4b") - const alias = await import("stylelint4b/alias") - - await alias.defineAliases({ - // configs - [require.resolve("stylelint-config-html")]: import( - "stylelint-config-html" - ).then((o) => adjustConfig(o)), - "stylelint-config-html": import("stylelint-config-html"), - [require.resolve("stylelint-config-html/html")]: import( - "stylelint-config-html/html" - ).then((o) => adjustConfig(o)), - [require.resolve("stylelint-config-html/vue")]: import( - "stylelint-config-html/vue" - ).then((o) => adjustConfig(o)), - [require.resolve("stylelint-config-html/php")]: import( - "stylelint-config-html/php" - ).then((o) => adjustConfig(o)), - [require.resolve("stylelint-config-html/svelte")]: import( - "stylelint-config-html/svelte" - ).then((o) => adjustConfig(o)), - [require.resolve("stylelint-config-html/astro")]: import( - "stylelint-config-html/astro" - ).then((o) => adjustConfig(o)), - [require.resolve("stylelint-config-html/xml")]: import( - "stylelint-config-html/xml" - ).then((o) => adjustConfig(o)), - // - [require.resolve("stylelint-stylus/base-config")]: import( - "stylelint-stylus/base-config" - ).then((o) => adjustConfig(o)), - ["stylelint-stylus/base-config"]: import( - "stylelint-stylus/base-config" - ).then((o) => adjustConfig(o)), - [require.resolve("stylelint-stylus/recommended")]: import( - "stylelint-stylus/recommended" - ).then((o) => adjustConfig(o)), - ["stylelint-stylus/recommended"]: import( - "stylelint-stylus/recommended" - ).then((o) => adjustConfig(o)), - "stylelint-stylus/standard": import("stylelint-stylus/standard").then( - (o) => adjustConfig(o), - ), - // plugins - "stylelint-stylus": import("stylelint-stylus"), - [require.resolve("stylelint-stylus")]: import("stylelint-stylus").then( - (o) => ({ ...o }), - ), - // syntax - "postcss-styl": import("postcss-styl").then((o) => ({ ...o })), - }) - - return { - stylelint4b: await stylelint4b, - alias, - } - - function adjustConfig({ ...config }) { - if (config.extends) { - config.extends = [config.extends] - .flat() - .map((e) => (typeof e === "number" ? String(e) : e)) - } - if (config.plugins) { - config.plugins = [config.plugins] - .flat() - .map((e) => (typeof e === "number" ? String(e) : e)) - } - if (config.overrides) { - config.overrides = [config.overrides] - .flat() - .map((o) => adjustConfig(o)) - } - return config - } -} diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js deleted file mode 100644 index c14af26..0000000 --- a/docs/.vuepress/config.js +++ /dev/null @@ -1,107 +0,0 @@ -const { - categories, - uncategorizedRules, - deprecatedRules, -} = require("../../scripts/lib/categories") - -const path = require("path") -// eslint-disable-next-line node/no-extraneous-require -- ignore -const webpack = require("webpack") - -function resolve(seg) { - return path.resolve(__dirname, seg) -} - -const extraCategories = [] -if (uncategorizedRules.length > 0) { - extraCategories.push({ - title: "Uncategorized", - collapsable: false, - children: uncategorizedRules.map(({ ruleName, fileName }) => [ - `/rules/${fileName}`, - ruleName, - ]), - }) -} -if (deprecatedRules.length > 0) { - extraCategories.push({ - title: "Deprecated", - collapsable: false, - children: deprecatedRules.map(({ ruleName, fileName }) => [ - `/rules/${fileName}`, - ruleName, - ]), - }) -} - -module.exports = { - base: "/stylelint-stylus/", - title: "stylelint-stylus", - description: "stylelint plugin for Stylus", - serviceWorker: true, - head: [ - // ["link", { rel: "icon", type: "image/png", href: "/logo.png" }] - ], - configureWebpack: { - resolve: { - symlinks: false, - alias: { - // eslint-disable-next-line node/no-extraneous-require -- ignore - stylus: require.resolve("stylus/lib/stylus"), - glob: require.resolve("./shim/glob"), - sax: require.resolve("./shim/sax"), - "stylelint/lib/reference/keywordSets": - require.resolve("./shim/empty"), - stylelint: resolve("../../node_modules/stylelint4b"), - "postcss-syntax": resolve( - "../../node_modules/stylelint4b/packages/postcss-syntax", - ), - postcss: resolve( - "../../node_modules/stylelint4b/packages/postcss", - ), - }, - }, - plugins: [ - new webpack.DefinePlugin({ - "process.version": JSON.stringify("v12.13.0"), - "process.env": "{}", - "process.platform": '"darwin"', - }), - ], - }, - themeConfig: { - repo: "stylus/stylelint-stylus", - docsRepo: "stylus/stylelint-stylus", - docsDir: "docs", - docsBranch: "main", - editLinks: true, - lastUpdated: true, - - nav: [ - { text: "Introduction", link: "/" }, - { text: "Playground", link: "/playground/" }, - ], - - sidebar: { - "/": [ - "/", - "/playground/", - - // Rules in each category. - ...categories - .map(({ title, rules: catRules }) => ({ - title: title.replace(/ \(.+?\)/u, ""), - collapsable: false, - children: catRules.map(({ ruleName, fileName }) => [ - `/rules/${fileName}`, - ruleName, - ]), - })) - .filter((menu) => Boolean(menu.children.length)), - - // Rules in no category. - ...extraCategories, - ], - }, - }, -} diff --git a/docs/.vuepress/enhanceApp.js b/docs/.vuepress/enhanceApp.js deleted file mode 100644 index 4e7cbcb..0000000 --- a/docs/.vuepress/enhanceApp.js +++ /dev/null @@ -1,15 +0,0 @@ -/* eslint node/no-unsupported-features/es-syntax: 0 -- ignore */ -export default () => - // { - // Vue, // the version of Vue being used in the VuePress app - // options, // the options for the root Vue instance - // router, // the router instance for the app - // siteData, // site metadata - // } - { - if (typeof window !== "undefined") { - if (typeof window.global === "undefined") { - window.global = {} - } - } - } diff --git a/docs/.vuepress/shim/empty.js b/docs/.vuepress/shim/empty.js deleted file mode 100644 index 4ba52ba..0000000 --- a/docs/.vuepress/shim/empty.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = {} diff --git a/docs/.vuepress/shim/glob.js b/docs/.vuepress/shim/glob.js deleted file mode 100644 index 4ba52ba..0000000 --- a/docs/.vuepress/shim/glob.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = {} diff --git a/docs/.vuepress/shim/sax.js b/docs/.vuepress/shim/sax.js deleted file mode 100644 index 4ba52ba..0000000 --- a/docs/.vuepress/shim/sax.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = {} diff --git a/docs/.vuepress/styles/index.styl b/docs/.vuepress/styles/index.styl deleted file mode 100644 index 02b89a5..0000000 --- a/docs/.vuepress/styles/index.styl +++ /dev/null @@ -1,56 +0,0 @@ -// playground -.theme-container - .sidebar - transition transform 0.2s ease - -.theme-container.playground - .content__default:not(.custom) - max-width 900px - margin 0 auto - padding 2rem 2.5rem - - .app - height calc(100vh - 70px) - - .sidebar-button - display block - - .navbar - padding-left 4rem - - .sidebar - top 0 - padding-top 3.6rem - transform translateX(-100%) - transition transform 0.2s ease - - .page - padding-left 0 - - .header-anchor - display none - -.theme-container.playground.sidebar-open - .sidebar - transform translateX(0) - -// playground layout -.theme-container.playground - .theme-default-content - position relative - - blockquote - position absolute - top 72px - right 48px - border-left 0 - - @media (max-width 600px) - font-size 0.8rem - - @media (max-width 550px) - top 100px - - @media (max-width 419px) - top 95px - font-size 0.7rem diff --git a/docs/README.md b/docs/index.md similarity index 93% rename from docs/README.md rename to docs/index.md index a2cbaff..e3cdd8f 100644 --- a/docs/README.md +++ b/docs/index.md @@ -4,7 +4,7 @@ title: "Introduction"

stylelint-stylus

-

Stylelint plugin for Stylus. +

Stylelint plugin for Stylus.

This plugin is still in an experimental state

@@ -38,7 +38,7 @@ This plugin allows us to check the [Stylus] with [Stylelint]. [Stylelint editor integrations](https://stylelint.io/user-guide/integrations/editor) are useful to check your code in real-time. -You can check on the [Online DEMO](./playground/). +You can check on the [Online DEMO](https://stylelint.io/demo/#N4Igxg9gJgpiBcID0SAEAVATgT1QZQBdsAbAVwGcBCAHQDsAjaXYO1VAMwloPlQEYALAAcAHkj4A6AKyoAEjGIA3GAQCWYAIYAaVBsyqNxHeQ21yAWnIx97ANytUAYmIQA5hFQtabNo0yxMc0wNKFUKXilRe29UAF86eNo6FFQAMWIYEVV6DNRybG4NETpGKGwHTm5+YTFJGXklFXVtXX1DY1MLKxs6B3pSAgIuPoGh2gl+weGY1VohAYBtIiEYAF5qEEmxjYBdB1n5giXsFfWQclJ6AFtVAl2HXwh-ayCQsPJUSOKk2hSAWVUWTMJSeAVeoQoAApFIYAJQOcwAdxg9AA1rdzH4wcEIeReDDiAirhAAF6Y0EvHHvfGGPoUwJU8KoAkOEqjLieOnPBlvKFfWHRRIgLQgdiqDIAOQ0VzgiEy0qEGQk5CIxGF4C4YtcCBAXjYG0yBBgtCg5A2vAWD1QGxVJAUswIllVFCQKtMUD0UA2Dj2tFi6sgtC1qSeVw0BB1ACtyFx1bAhOQdXrredVfbuOaU8RwzAVRstKzU3biA6nSQKJmNtmjXmQAkQLEgA). ## :cd: Installation @@ -211,9 +211,8 @@ These rules relate to style guidelines. ## License -See the [LICENSE] file for license rights and limitations (MIT). +See the [LICENSE](https://github.com/stylus/stylelint-stylus/blob/main/LICENSE) file for license rights and limitations (MIT). -[license]: ./LICENSE [stylelint]: https://stylelint.io/ [stylus]: https://stylus-lang.com/ [vscode extension]: https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint diff --git a/docs/playground/README.md b/docs/playground/README.md deleted file mode 100644 index 30089ac..0000000 --- a/docs/playground/README.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -pageClass: "playground" ---- - -# Playground - -> This playground is built using [stylelint4b](https://ota-meshi.github.io/stylelint4b/). - - - -The playground is [here](https://stylus.github.io/stylelint-stylus/playground/)!! - - diff --git a/docs/rules/at-extend-style.md b/docs/rules/at-extend-style.md index d3d99c5..50caa47 100644 --- a/docs/rules/at-extend-style.md +++ b/docs/rules/at-extend-style.md @@ -22,9 +22,8 @@ This rule enforces [@extend] style. ### `""@extend"` - - ```styl +/* stylelint rules config: {"stylus/at-extend-style": "@extend"} */ a // ✓ GOOD @extend .foo; @@ -35,13 +34,10 @@ a @extends .foo; ``` - - ### `"@extends"` - - ```styl +/* stylelint rules config: {"stylus/at-extend-style": "@extends"} */ a // ✓ GOOD @extends .foo; @@ -52,8 +48,6 @@ a @extend .foo; ``` - - ## :books: Further reading - [Stylus - @EXTEND] diff --git a/docs/rules/at-rule-no-unknown.md b/docs/rules/at-rule-no-unknown.md index 84d239b..24d07bd 100644 --- a/docs/rules/at-rule-no-unknown.md +++ b/docs/rules/at-rule-no-unknown.md @@ -20,9 +20,8 @@ See [stylelint - at-rule-no-unknown - Options](https://stylelint.io/user-guide/r ### `true` - - ```styl +/* stylelint rules config: {"stylus/at-rule-no-unknown": true} */ // ✓ GOOD @media (max-width: 960px) {} @media (max-width: 960px) @@ -43,8 +42,6 @@ See [stylelint - at-rule-no-unknown - Options](https://stylelint.io/user-guide/r color red ``` - - ## :couple: Related rules - [at-rule-no-unknown] diff --git a/docs/rules/declaration-colon.md b/docs/rules/declaration-colon.md index f7f88a4..fcf567f 100644 --- a/docs/rules/declaration-colon.md +++ b/docs/rules/declaration-colon.md @@ -22,9 +22,8 @@ This rule require or disallow declaration colons. ### `"always"` - - ```styl +/* stylelint rules config: {"stylus/declaration-colon": "always"} */ a // ✓ GOOD color: red @@ -32,13 +31,10 @@ a color red ``` - - ### `"never"` - - ```styl +/* stylelint rules config: {"stylus/declaration-colon": "never"} */ a // ✓ GOOD color red @@ -46,8 +42,6 @@ a color: red ``` - - ## :books: Further reading - [Stylus - Features] diff --git a/docs/rules/hash-object-property-comma.md b/docs/rules/hash-object-property-comma.md index 2d62e61..a35c38c 100644 --- a/docs/rules/hash-object-property-comma.md +++ b/docs/rules/hash-object-property-comma.md @@ -30,9 +30,8 @@ This rule require or disallow commas in [hash object] properties. ### `"always"` - - ```styl +/* stylelint rules config: {"stylus/hash-object-property-comma": "always"} */ // ✓ GOOD foo = { bar: baz, @@ -48,13 +47,10 @@ foo = { foo = { bar: baz, baz: raz } ``` - - ### `"never"` - - ```styl +/* stylelint rules config: {"stylus/hash-object-property-comma": "never"} */ // ✓ GOOD foo = { bar: baz @@ -70,13 +66,10 @@ foo = { foo = { bar: baz, baz: raz, } ``` - - ### `[ "always", { "trailing": "never" } ]` - - ```styl +/* stylelint rules config: {"stylus/hash-object-property-comma": ["always", { "trailing": "never" }]} */ // ✓ GOOD foo = { bar: baz, @@ -96,8 +89,6 @@ foo = { foo = { bar: baz, baz: raz, } ``` - - ## :books: Further reading - [Stylus - HASHES] diff --git a/docs/rules/media-feature-colon.md b/docs/rules/media-feature-colon.md index e4868d0..46dc100 100644 --- a/docs/rules/media-feature-colon.md +++ b/docs/rules/media-feature-colon.md @@ -22,9 +22,8 @@ This rule require or disallow media feature colons. ### `"always"` - - ```styl +/* stylelint rules config: {"stylus/media-feature-colon": "always"} */ // ✓ GOOD @media (min-width: 600px) padding 20px @@ -34,13 +33,10 @@ This rule require or disallow media feature colons. padding 20px ``` - - ### `"never"` - - ```styl +/* stylelint rules config: {"stylus/media-feature-colon": "never"} */ // ✓ GOOD @media (min-width 600px) padding 20px @@ -50,8 +46,6 @@ This rule require or disallow media feature colons. padding 20px ``` - - ## :books: Further reading - [Stylus - Features] diff --git a/docs/rules/no-at-require.md b/docs/rules/no-at-require.md index f6aa3de..9c19072 100644 --- a/docs/rules/no-at-require.md +++ b/docs/rules/no-at-require.md @@ -21,9 +21,8 @@ This rule enforces [@extend] style. ### `true` - - ```styl +/* stylelint rules config: {"stylus/no-at-require": true} */ // ✓ GOOD @import './foo.styl' @@ -31,8 +30,6 @@ This rule enforces [@extend] style. @require './foo.styl' ``` - - ## :books: Further reading - [Stylus - @IMPORT AND @REQUIRE] diff --git a/docs/rules/pythonic.md b/docs/rules/pythonic.md index bf0e9d8..782b456 100644 --- a/docs/rules/pythonic.md +++ b/docs/rules/pythonic.md @@ -30,9 +30,8 @@ This rule enforces pythonic or brace style. ### `"always"` - - ```styl +/* stylelint rules config: {"stylus/pythonic": "always"} */ // ✓ GOOD .foo color: red; @@ -50,13 +49,10 @@ bar = @block { } ``` - - ### `"never"` - - ```styl +/* stylelint rules config: {"stylus/pythonic": "never"} */ // ✓ GOOD .foo { color: red; @@ -74,13 +70,10 @@ bar = height: 20px; ``` - - ### `[ "always", { "atblock": "never" } ]` - - ```styl +/* stylelint rules config: {"stylus/pythonic": ["always", {"atblock": "never"}]} */ // ✓ GOOD .foo color: red; @@ -98,13 +91,10 @@ bar = ``` - - ### `[ "never", { "atblock": "always" } ]` - - ```styl +/* stylelint rules config: {"stylus/pythonic": ["never", {"atblock": "always"}]} */ // ✓ GOOD .foo { color: red; @@ -122,8 +112,6 @@ bar = @block { } ``` - - ## :books: Further reading - [Stylus - SELECTORS - Indentation] diff --git a/docs/rules/selector-list-comma.md b/docs/rules/selector-list-comma.md index f5b4b80..4cac73f 100644 --- a/docs/rules/selector-list-comma.md +++ b/docs/rules/selector-list-comma.md @@ -22,9 +22,8 @@ This rule require or disallow selector list comma. ### `"always"` - - ```styl +/* stylelint rules config: {"stylus/selector-list-comma": "always"} */ // ✓ GOOD .foo, .bar @@ -36,13 +35,10 @@ This rule require or disallow selector list comma. color red ``` - - ### `"never"` - - ```styl +/* stylelint rules config: {"stylus/selector-list-comma": "never"} */ // ✓ GOOD .foo .bar @@ -54,8 +50,6 @@ This rule require or disallow selector list comma. color red ``` - - ## :books: Further reading - [Stylus - SELECTORS - Rule Sets] diff --git a/docs/rules/semicolon.md b/docs/rules/semicolon.md index 5bede49..ee2fec1 100644 --- a/docs/rules/semicolon.md +++ b/docs/rules/semicolon.md @@ -22,9 +22,8 @@ This rule require or disallow semicolons. ### `"always"` - - ```styl +/* stylelint rules config: {"stylus/semicolon": "always"} */ a // ✓ GOOD color red; @@ -32,13 +31,10 @@ a color red ``` - - ### `"never"` - - ```styl +/* stylelint rules config: {"stylus/semicolon": "never"} */ a // ✓ GOOD color red @@ -46,8 +42,6 @@ a color red; ``` - - ## :couple: Related rules - [declaration-block-trailing-semicolon] diff --git a/docs/rules/single-line-comment-double-slash-space-after.md b/docs/rules/single-line-comment-double-slash-space-after.md index 7621d50..72c063f 100644 --- a/docs/rules/single-line-comment-double-slash-space-after.md +++ b/docs/rules/single-line-comment-double-slash-space-after.md @@ -22,9 +22,8 @@ This rule require or disallow whitespace after the double-slash of single-line c ### `"always"` - - ```styl +/* stylelint rules config: {"stylus/single-line-comment-double-slash-space-after": "always"} */ // ✓ GOOD // OK // OK @@ -33,13 +32,10 @@ This rule require or disallow whitespace after the double-slash of single-line c //NG ``` - - ### `"never"` - - ```styl +/* stylelint rules config: {"stylus/single-line-comment-double-slash-space-after": "never"} */ //✓ GOOD //OK @@ -48,8 +44,6 @@ This rule require or disallow whitespace after the double-slash of single-line c // NG ``` - - ## :couple: Related rules - [comment-whitespace-inside] diff --git a/docs/rules/single-line-comment-no-empty.md b/docs/rules/single-line-comment-no-empty.md index 4ff2759..05e0591 100644 --- a/docs/rules/single-line-comment-no-empty.md +++ b/docs/rules/single-line-comment-no-empty.md @@ -18,9 +18,8 @@ This rule reports empty single-line comments. ### `true` - - ```styl +/* stylelint rules config: {"stylus/single-line-comment-no-empty": true} */ // ✓ GOOD // single line comment @@ -29,8 +28,6 @@ This rule reports empty single-line comments. // ``` - - ## :couple: Related rules - [comment-no-empty] diff --git a/docs/rules/single-line-comment.md b/docs/rules/single-line-comment.md index 48a18de..3478b88 100644 --- a/docs/rules/single-line-comment.md +++ b/docs/rules/single-line-comment.md @@ -22,9 +22,8 @@ This rule enforces comment style where single-line comments are allowed. ### `"always"` - - ```styl +/* stylelint rules config: {"stylus/single-line-comment": "always"} */ // ✓ GOOD // single line comment .foo { // single line comment @@ -47,13 +46,10 @@ This rule enforces comment style where single-line comments are allowed. } ``` - - ### `"never"` - - ```styl +/* stylelint rules config: {"stylus/single-line-comment": "never"} */ /* ✓ GOOD */ /* multi line comment */ .foo { /* multi line comment */ @@ -65,8 +61,6 @@ This rule enforces comment style where single-line comments are allowed. } ``` - - ## :books: Further reading - [Stylus - COMMENTS] diff --git a/lib/rules/semicolon.js b/lib/rules/semicolon.js index 17c52e3..0af7b97 100644 --- a/lib/rules/semicolon.js +++ b/lib/rules/semicolon.js @@ -5,6 +5,7 @@ const { } = require("stylelint") const { inCssLiteral, isObjectProperty } = require("../utils/nodes") const { hasBlock } = require("../utils/ast") +const postcssStyl = require("postcss-styl") const ruleName = "stylus/semicolon" @@ -80,7 +81,7 @@ function rule(expectation, _secondary, context) { report({ message: messages.expected, node, - index: node.toString().trim().length, + index: getLength(node), result, ruleName, }) @@ -102,7 +103,7 @@ function rule(expectation, _secondary, context) { report({ message: messages.rejected, node, - index: node.toString().trim().length, + index: getLength(node), result, ruleName, }) @@ -121,3 +122,9 @@ function findLastNode(nodes) { } return null } + +function getLength(node) { + let str = "" + postcssStyl.stringify(node, (s) => (str += s)) + return str.length +} diff --git a/package.json b/package.json index 48d2ba7..b462210 100644 --- a/package.json +++ b/package.json @@ -22,9 +22,10 @@ "preversion": "npm run update && npm run test", "version": "npm run lint -- --fix && git add .", "update": "node ./scripts/update.js", - "docs:watch": "vuepress dev docs", - "docs:build": "vuepress build docs", - "stylelint": "stylelint \"docs/.vuepress/**/*.css\" \"docs/.vuepress/**/*.vue\" \"docs/.vuepress/**/*.styl\"", + "docs:watch": "vitepress dev docs", + "docs:build": "vitepress build docs", + "docs:build-and-preview": "npm run docs:build && npx http-server docs/.vitepress/dist", + "stylelint": "stylelint \"docs/.vitepress/**/*.css\" \"docs/.vitepress/**/*.vue\" \"docs/.vitepress/**/*.styl\"", "make-alias-package": "node ./scripts/make-alias-package.js" }, "repository": { @@ -58,6 +59,7 @@ }, "devDependencies": { "@ota-meshi/eslint-plugin": "^0.10.0", + "@shikijs/vitepress-twoslash": "^1.2.2", "@types/lodash": "^4.14.149", "cross-env": "^7.0.2", "eslint": "^8.0.0", @@ -80,9 +82,7 @@ "stylelint": "^16.0.0", "stylelint-config-recommended": "^14.0.0", "stylelint-stylus": "file:.", - "stylelint4b": "^14.15.1-0", - "vue-stylelint-editor": "^0.6.0", - "vuepress": "^1.4.0" + "vitepress": "^1.0.1" }, "dependencies": { "html-tags": "^3.1.0", diff --git a/scripts/update-readme.js b/scripts/update-readme.js index 3ac1147..fd72598 100644 --- a/scripts/update-readme.js +++ b/scripts/update-readme.js @@ -89,7 +89,7 @@ fs.writeFileSync( ), ) -const docsReadmeFilePath = path.resolve(__dirname, "../docs/README.md") +const docsReadmeFilePath = path.resolve(__dirname, "../docs/index.md") fs.writeFileSync( docsReadmeFilePath, `--- @@ -102,5 +102,9 @@ ${fs .replace( /\(https:\/\/stylus.github.io\/stylelint-stylus\/(.*?)(\.html)?\)/gu, (_$0, $1, $2) => `(./${$1}${($2 === ".html" ? ".md" : $2) || ""})`, + ) + .replace( + "[LICENSE](./LICENSE)", + "[LICENSE](https://github.com/stylus/stylelint-stylus/blob/main/LICENSE)", )}`, )