Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use vitepress & twoslash #30

Merged
merged 3 commits into from
Mar 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
node_modules
/test-file
/tests/fixtures
!/docs/.vuepress
/docs/.vuepress/dist
!/docs/.vitepress
/docs/.vitepress/dist
/docs/.vitepress/cache
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ dist
# vuepress build output
.vuepress/dist

# vitepress build output
/docs/.vitepress/dist
/docs/.vitepress/cache

# Serverless directories
.serverless/

Expand All @@ -108,3 +112,5 @@ dist
/index.html
/alias-package


!docs/.vitepress/twoslash-stylelint/dist
5 changes: 3 additions & 2 deletions .stylelintignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
!/docs/.vuepress
/docs/.vuepress/dist
!/docs/.vitepress
/docs/.vitepress/dist
/docs/.vitepress/cache
/.nyc_output
/coverage
node_modules
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<h1 align="center">stylelint-stylus</h1>

<p align="center"><a href="https://stylelint.io/" alt="Stylelint">Stylelint</a> plugin for <a href="https://stylus-lang.com/" alt="Stylus">Stylus</a>.
<p align="center"><a href="https://stylelint.io/" alt="Stylelint">Stylelint</a> plugin for <a href="https://stylus-lang.com/" alt="Stylus">Stylus</a>.</p>

<p align="center"><b><i>This plugin is still in an experimental state</i></b></p>

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
140 changes: 140 additions & 0 deletions docs/.vitepress/config.mjs
Original file line number Diff line number Diff line change
@@ -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,
],
},
],
},
},
})
}
13 changes: 13 additions & 0 deletions docs/.vitepress/stylelint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"use strict"

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,
},
}
13 changes: 13 additions & 0 deletions docs/.vitepress/theme/index.ts
Original file line number Diff line number Diff line change
@@ -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;
13 changes: 13 additions & 0 deletions docs/.vitepress/theme/style.css
Original file line number Diff line number Diff line change
@@ -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;
}
33 changes: 33 additions & 0 deletions docs/.vitepress/twoslash-stylelint/index.d.mts
Original file line number Diff line number Diff line change
@@ -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 };
81 changes: 81 additions & 0 deletions docs/.vitepress/twoslash-stylelint/index.mjs
Original file line number Diff line number Diff line change
@@ -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 }
17 changes: 17 additions & 0 deletions docs/.vitepress/twoslash-stylelint/stylelint-worker.mjs
Original file line number Diff line number Diff line change
@@ -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,
}
}
12 changes: 0 additions & 12 deletions docs/.vuepress/.eslintrc.js

This file was deleted.

Loading
Loading