From caeb7273444c929c1ce87385b30b4b517a8bfd6f Mon Sep 17 00:00:00 2001 From: winston Date: Sat, 18 Nov 2023 05:28:02 +0100 Subject: [PATCH] ci(lint): refactor & handle more errors --- src/deno.json | 3 - src/deno.lock | 45 ++++++------ src/lint/file-checker.ts | 47 +++++++++++++ src/lint/logger.ts | 39 ++++++++--- src/lint/main.ts | 145 ++++++++------------------------------- src/lint/metadata.ts | 81 ++++++++++++++++++++++ src/lint/stylelint.ts | 35 +++++++++- 7 files changed, 239 insertions(+), 156 deletions(-) create mode 100644 src/lint/file-checker.ts create mode 100644 src/lint/metadata.ts diff --git a/src/deno.json b/src/deno.json index 10541ee341..aa13247751 100644 --- a/src/deno.json +++ b/src/deno.json @@ -2,10 +2,7 @@ "imports": { "@/": "./", "std/": "https://deno.land/std@0.206.0/", - "catppuccin-repo/": "https://raw.githubusercontent.com/catppuccin/catppuccin/91d6b5433730103c504dcf43583b594e418ee7c1/", - "globber": "https://deno.land/x/globber@0.1.0/mod.ts", - "@actions/core": "npm:@actions/core@1.10.1", "@octokit/rest": "npm:@octokit/rest@20.0.2", "usercss-meta": "npm:usercss-meta@0.12.0", diff --git a/src/deno.lock b/src/deno.lock index 562f9e39c8..b638cf7d09 100644 --- a/src/deno.lock +++ b/src/deno.lock @@ -2,22 +2,16 @@ "version": "3", "packages": { "specifiers": { - "npm:@actions/core": "npm:@actions/core@1.10.1", "npm:@actions/core@1.10.1": "npm:@actions/core@1.10.1", "npm:@octokit/rest@20.0.2": "npm:@octokit/rest@20.0.2_@octokit+core@5.0.1", "npm:@types/less": "npm:@types/less@3.0.6", "npm:ajv@8.12.0": "npm:ajv@8.12.0", "npm:chalk@5.3.0": "npm:chalk@5.3.0", - "npm:less": "npm:less@4.2.0", "npm:less@4.2.0": "npm:less@4.2.0", "npm:postcss-less": "npm:postcss-less@6.0.0_postcss@8.4.31", - "npm:postcss-less@^6.0.0": "npm:postcss-less@6.0.0_postcss@8.4.31", "npm:stylelint": "npm:stylelint@15.11.0_@csstools+css-tokenizer@2.2.1_@csstools+css-parser-algorithms@2.3.2__@csstools+css-tokenizer@2.2.1_postcss-selector-parser@6.0.13_postcss@8.4.31", "npm:stylelint-config-recommended": "npm:stylelint-config-recommended@13.0.0_stylelint@15.11.0__@csstools+css-tokenizer@2.2.1__@csstools+css-parser-algorithms@2.3.2___@csstools+css-tokenizer@2.2.1__postcss-selector-parser@6.0.13__postcss@8.4.31", "npm:stylelint-config-standard": "npm:stylelint-config-standard@34.0.0_stylelint@15.11.0__@csstools+css-tokenizer@2.2.1__@csstools+css-parser-algorithms@2.3.2___@csstools+css-tokenizer@2.2.1__postcss-selector-parser@6.0.13__postcss@8.4.31", - "npm:stylelint-config-standard@^34.0.0": "npm:stylelint-config-standard@34.0.0_stylelint@15.11.0__@csstools+css-tokenizer@2.2.1__@csstools+css-parser-algorithms@2.3.2___@csstools+css-tokenizer@2.2.1__postcss-selector-parser@6.0.13__postcss@8.4.31", - "npm:stylelint@^15.11.0": "npm:stylelint@15.11.0_@csstools+css-tokenizer@2.2.1_@csstools+css-parser-algorithms@2.3.2__@csstools+css-tokenizer@2.2.1_postcss-selector-parser@6.0.13_postcss@8.4.31", - "npm:usercss-meta": "npm:usercss-meta@0.12.0", "npm:usercss-meta@0.12.0": "npm:usercss-meta@0.12.0" }, "npm": { @@ -434,8 +428,8 @@ "reusify": "reusify@1.0.4" } }, - "file-entry-cache@7.0.1": { - "integrity": "sha512-uLfFktPmRetVCbHe5UPuekWrQ6hENufnA46qEGbfACkK5drjTTdQYUragRgMjHldcbYG+nslUerqMPjbBSHXjQ==", + "file-entry-cache@7.0.2": { + "integrity": "sha512-TfW7/1iI4Cy7Y8L6iqNdZQVvdXn0f8B4QcIXmkIbtTIe/Okm/nSlHb4IwGzRVOd3WfSieCgvf5cMzEfySAIl0g==", "dependencies": { "flat-cache": "flat-cache@3.2.0" } @@ -510,7 +504,7 @@ "array-union": "array-union@2.1.0", "dir-glob": "dir-glob@3.0.1", "fast-glob": "fast-glob@3.3.2", - "ignore": "ignore@5.2.4", + "ignore": "ignore@5.3.0", "merge2": "merge2@1.4.1", "slash": "slash@3.0.0" } @@ -557,8 +551,8 @@ "safer-buffer": "safer-buffer@2.1.2" } }, - "ignore@5.2.4": { - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "ignore@5.3.0": { + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "dependencies": {} }, "image-size@0.5.5": { @@ -1096,12 +1090,12 @@ "debug": "debug@4.3.4", "fast-glob": "fast-glob@3.3.2", "fastest-levenshtein": "fastest-levenshtein@1.0.16", - "file-entry-cache": "file-entry-cache@7.0.1", + "file-entry-cache": "file-entry-cache@7.0.2", "global-modules": "global-modules@2.0.0", "globby": "globby@11.1.0", "globjoin": "globjoin@0.1.4", "html-tags": "html-tags@3.3.1", - "ignore": "ignore@5.2.4", + "ignore": "ignore@5.3.0", "import-lazy": "import-lazy@4.0.0", "imurmurhash": "imurmurhash@0.1.4", "is-plain-object": "is-plain-object@5.0.0", @@ -1345,6 +1339,20 @@ "https://deno.land/std@0.206.0/collections/zip.ts": "d5def5cf3a0a3fa167956b7eb2ebdc3aca63a41f7ebdfac8c0d1c44fa0dd588d", "https://deno.land/std@0.206.0/flags/mod.ts": "0948466fc437f017f00c0b972a422b3dc3317a790bcf326429d23182977eaf9f", "https://deno.land/std@0.206.0/fmt/colors.ts": "c51c4642678eb690dcf5ffee5918b675bf01a33fba82acf303701ae1a4f8c8d9", + "https://deno.land/std@0.206.0/fmt/printf.ts": "b4ca7dc4b2323b2614c7d11b3e6dc80442e5d56c33665cdf9b9de0dabb80f9ec", + "https://deno.land/std@0.206.0/fs/_util.ts": "fbf57dcdc9f7bc8128d60301eece608246971a7836a3bb1e78da75314f08b978", + "https://deno.land/std@0.206.0/fs/copy.ts": "ca19e4837965914471df38fbd61e16f9e8adfe89f9cffb0c83615c83ea3fc2bf", + "https://deno.land/std@0.206.0/fs/empty_dir.ts": "0b4a2508232446eed232ad1243dd4b0f07ac503a281633ae1324d1528df70964", + "https://deno.land/std@0.206.0/fs/ensure_dir.ts": "dc64c4c75c64721d4e3fb681f1382f803ff3d2868f08563ff923fdd20d071c40", + "https://deno.land/std@0.206.0/fs/ensure_file.ts": "39ac83cc283a20ec2735e956adf5de3e8a3334e0b6820547b5772f71c49ae083", + "https://deno.land/std@0.206.0/fs/ensure_link.ts": "c15e69c48556d78aae31b83e0c0ece04b7b8bc0951412f5b759aceb6fde7f0ac", + "https://deno.land/std@0.206.0/fs/ensure_symlink.ts": "b389c8568f0656d145ac7ece472afe710815cccbb2ebfd19da7978379ae143fe", + "https://deno.land/std@0.206.0/fs/eol.ts": "f1f2eb348a750c34500741987b21d65607f352cf7205f48f4319d417fff42842", + "https://deno.land/std@0.206.0/fs/exists.ts": "cb59a853d84871d87acab0e7936a4dac11282957f8e195102c5a7acb42546bb8", + "https://deno.land/std@0.206.0/fs/expand_glob.ts": "4f98c508fc9e40d6311d2f7fd88aaad05235cc506388c22dda315e095305811d", + "https://deno.land/std@0.206.0/fs/mod.ts": "bc3d0acd488cc7b42627044caf47d72019846d459279544e1934418955ba4898", + "https://deno.land/std@0.206.0/fs/move.ts": "b4f8f46730b40c32ea3c0bc8eb0fd0e8139249a698883c7b3756424cf19785c9", + "https://deno.land/std@0.206.0/fs/walk.ts": "c1e6b43f72a46e89b630140308bd51a4795d416a416b4cfb7cd4bd1e25946723", "https://deno.land/std@0.206.0/path/_common/assert_path.ts": "061e4d093d4ba5aebceb2c4da3318bfe3289e868570e9d3a8e327d91c2958946", "https://deno.land/std@0.206.0/path/_common/basename.ts": "0d978ff818f339cd3b1d09dc914881f4d15617432ae519c1b8fdc09ff8d3789a", "https://deno.land/std@0.206.0/path/_common/common.ts": "9e4233b2eeb50f8b2ae10ecc2108f58583aea6fd3e8907827020282dc2b76143", @@ -1366,6 +1374,7 @@ "https://deno.land/std@0.206.0/path/extname.ts": "2da4e2490f3b48b7121d19fb4c91681a5e11bd6bd99df4f6f47d7a71bb6ecdf2", "https://deno.land/std@0.206.0/path/format.ts": "3457530cc85d1b4bab175f9ae73998b34fd456c830d01883169af0681b8894fb", "https://deno.land/std@0.206.0/path/from_file_url.ts": "e7fa233ea1dff9641e8d566153a24d95010110185a6f418dd2e32320926043f8", + "https://deno.land/std@0.206.0/path/glob.ts": "b8333cbb4aaaeb54ca6d6c43e0b69fb13c9481c69ed7a3c64a3d0d9daf2af769", "https://deno.land/std@0.206.0/path/glob_to_regexp.ts": "74d7448c471e293d03f05ccb968df4365fed6aaa508506b6325a8efdc01d8271", "https://deno.land/std@0.206.0/path/is_absolute.ts": "67232b41b860571c5b7537f4954c88d86ae2ba45e883ee37d3dec27b74909d13", "https://deno.land/std@0.206.0/path/is_glob.ts": "567dce5c6656bdedfc6b3ee6c0833e1e4db2b8dff6e62148e94a917f289c06ad", @@ -1458,16 +1467,6 @@ "https://deno.land/std@0.206.0/yaml/schema/mod.ts": "4472e827bab5025e92bc2eb2eeefa70ecbefc64b2799b765c69af84822efef32", "https://deno.land/std@0.206.0/yaml/stringify.ts": "fffc09c65c68d3d63f8159e8cbaa3f489bc20a8e55b4fbb61a8c2e9f914d1d02", "https://deno.land/std@0.206.0/yaml/type.ts": "65553da3da3c029b6589c6e4903f0afbea6768be8fca61580711457151f2b30f", - "https://deno.land/x/globber@0.1.0/mod.ts": "971e58757909b2ef722e3dda1125aea8f5694601203ad835bdfc020f202bd5b8", - "https://deno.land/x/globber@0.1.0/src/create_matcher.ts": "85be3a6d67376905521aed9da51db756d1ee747ebd0d52b88fc7b78a6831a393", - "https://deno.land/x/globber@0.1.0/src/deps.ts": "179ba170213f7a35b7b794c409e7ca523da58644139c053721f93575dcbe616e", - "https://deno.land/x/globber@0.1.0/src/errors.ts": "aacdb19cda93423ca25c03089eeaa2d613ef09a631e6f41f86e457f64762cf76", - "https://deno.land/x/globber@0.1.0/src/get_path.ts": "1da42fbcc1451d48f21edf7a1ceecbf19fd34845fc2962fab2d70bb804a3a03b", - "https://deno.land/x/globber@0.1.0/src/globber.ts": "814cc13ddb31f9112b44def2815844c427f3ed0a145d1707f673b3ed4d018003", - "https://deno.land/x/globber@0.1.0/src/junk.ts": "68cdbfc55d9e4664200793c31f0cc686a8e75939fd51dd9013df8328444c2040", - "https://deno.land/x/globber@0.1.0/src/meta.ts": "989705d65480e8be2c5b0ca4fa8bf96ee0669f2336497b768f8d4d669e4ad95c", - "https://deno.land/x/globber@0.1.0/src/normalize_path.ts": "08ffa246c27dfbc345f4d096455921027079c7d1ef58555bb6cfb9b8bdd64415", - "https://deno.land/x/globber@0.1.0/src/utils.ts": "d7b0c1db9e627c0ee2e4e1d435c605f5c89e570984bd790c435db54798eafb9d", "https://raw.githubusercontent.com/catppuccin/catppuccin/91d6b5433730103c504dcf43583b594e418ee7c1/resources/ports.schema.json": "f1bfc1f4c68af258cd2f1a254d70069b7d254ab0cfe298b9b52bcd78299d8e40" } } diff --git a/src/lint/file-checker.ts b/src/lint/file-checker.ts new file mode 100644 index 0000000000..8802dc4cd7 --- /dev/null +++ b/src/lint/file-checker.ts @@ -0,0 +1,47 @@ +import { exists } from "std/fs/mod.ts"; +import { join, relative } from "std/path/mod.ts"; +import core from "@actions/core"; + +import { REPO_ROOT } from "@/deps.ts"; +import { log } from "./logger.ts"; +import chalk from "chalk"; + +const requiredFiles = [ + "catppuccin.user.css", + ...["latte", "frappe", "macchiato", "mocha", "catwalk"].map((f) => + join("assets", `${f}.webp`) + ), +]; + +export const checkForMissingFiles = async () => { + const stylesRoot = join(REPO_ROOT, "styles"); + + const missingFiles: string[] = []; + for await (const entry of Deno.readDir(stylesRoot)) { + if (!entry.isDirectory) continue; + const styleRoot = join(stylesRoot, entry.name); + + await Promise.all(requiredFiles.map(async (f) => { + const fp = join(styleRoot, f); + const rfp = relative(REPO_ROOT, fp); + + if (!(await exists(fp))) { + missingFiles.push(rfp); + } + })); + } + + // only write summary if running in github actions + if (Deno.env.has("GITHUB_ACTIONS")) { + await core.summary + .addHeading("Missing files") + .addList(missingFiles) + .write(); + } else { + missingFiles.map((f) => { + log(chalk.red(`Missing file:`) + ` ${f}`, { file: f }, "error"); + }); + } + + return missingFiles.length === 0; +}; diff --git a/src/lint/logger.ts b/src/lint/logger.ts index 7900659347..c8eba67769 100644 --- a/src/lint/logger.ts +++ b/src/lint/logger.ts @@ -1,16 +1,17 @@ +import { sprintf } from "std/fmt/printf.ts"; import chalk from "chalk"; import core from "@actions/core"; -export type LoggerProps = core.AnnotationProperties & { - content?: string; -}; +export type LoggerProps = core.AnnotationProperties & { content?: string }; const pretty_print = ( message: string, props: LoggerProps, severity: "error" | "warning" = "warning", ) => { - const startLine = props.startLine ?? 0; + const { file, startColumn, startLine } = props; + if (!startLine) return console.log(message); + const lines = (props.content ?? "").split("\n"); const error = [ @@ -29,13 +30,33 @@ const pretty_print = ( } }).join(""); + const pad = startLine.toString().length; console.log( [ - `${props.file}:${chalk.grey(`${props.startLine}:${props.startColumn}`)}`, - ` ┃${chalk.dim(lines[startLine - 2])}`, - ` ┃${chalk.grey(line)}`, - ` ┃${chalk.dim(lines[startLine])}`, - error, + chalk.underline( + sprintf( + "%s%s%d%s%d", + file, + startLine ? ":" : "", + startLine ?? "", + startColumn ? ":" : "", + startColumn ?? "", + ), + ), + sprintf( + "%*s│ %s", + pad, + chalk.dim(startLine - 1), + chalk.dim(lines[startLine - 2]), + ), + sprintf("%*s│ %s", pad, chalk.bold(startLine), line), + sprintf( + "%*s│ %s", + pad, + chalk.dim(startLine + 1), + chalk.dim(lines[startLine]), + ), + sprintf("%*s╰─► %s", pad, "", error), undefined, ].join("\n"), ); diff --git a/src/lint/main.ts b/src/lint/main.ts index 2eae00f801..f510f36ca4 100755 --- a/src/lint/main.ts +++ b/src/lint/main.ts @@ -1,146 +1,55 @@ -#!/usr/bin/env -S deno run --allow-read --allow-write --allow-env --allow-sys=uid,gid - -// TODO: remove this once types for usercss-meta are available -// deno-lint-ignore-file no-explicit-any +#!/usr/bin/env -S deno run -A +import { walk } from "std/fs/mod.ts"; import { parse as parseFlags } from "std/flags/mod.ts"; import { basename, dirname, join, relative } from "std/path/mod.ts"; -import { globber } from "globber"; -import core from "@actions/core"; -import chalk from "chalk"; // @deno-types="npm:@types/less"; import less from "less"; -import usercssMeta from "usercss-meta"; -import { lint } from "./stylelint.ts"; + import { REPO_ROOT } from "@/deps.ts"; -import { log, LoggerProps } from "./logger.ts"; +import { checkForMissingFiles } from "./file-checker.ts"; +import { log } from "./logger.ts"; +import { verifyMetadata } from "./metadata.ts"; +import { lint } from "./stylelint.ts"; const flags = parseFlags(Deno.args, { boolean: ["fix"] }); - -const iterator = globber({ - include: ["styles/**/catppuccin.user.css"], - cwd: REPO_ROOT, +const stylesheets = walk(join(REPO_ROOT, "styles"), { + includeFiles: true, + includeDirs: false, + includeSymlinks: false, + match: [/\.user.css$/], }); -const missingFiles: string[] = []; - -const assertions = (repo: string) => { - const pfx = "https://github.com/catppuccin/userstyles"; - return { - namespace: `github.com/catppuccin/userstyles/styles/${repo}`, - author: "Catppuccin", - license: "MIT", - preprocessor: "less", - homepageURL: `${pfx}/tree/main/styles/${repo}`, - updateURL: `${pfx}/raw/main/styles/${repo}/catppuccin.user.css`, - }; -}; - -for await (const entry of iterator) { - const repodir = dirname(entry.absolute); +for await (const entry of stylesheets) { + const repodir = dirname(entry.path); const repo = basename(repodir); + const file = relative(REPO_ROOT, entry.path); - const content = await Deno.readTextFile(entry.absolute); - - let metadata: Record = {}; - try { - metadata = usercssMeta.parse(content).metadata; - } catch (err) { - log(err, { file: entry.relative, content }, "error"); - } - - const assert = assertions(repo); - - Object.entries(assert).forEach(([k, v]) => { - const defacto = metadata[k]; - if (defacto !== v) { - const line = content.split("\n").findIndex((line) => line.includes(k)) + - 1; - - log( - [ - "Metadata", - chalk.bold(k), - "should be", - chalk.green(v), - "but is", - chalk.red(defacto), - ].join(" "), - { - file: entry.relative, - startLine: line !== 0 ? line : undefined, - content, - }, - "warning", - ); - } - }); + const content = await Deno.readTextFile(entry.path); + // verify the usercss metadata + const { globalVars, isLess } = await verifyMetadata(entry, content, repo) + .catch(() => ({ globalVars: {}, isLess: false })); // don't attempt to compile or lint non-less files - if (metadata.preprocessor !== assert.preprocessor) continue; - - const globalVars = Object.entries(metadata.vars) - .reduce((acc, [k, v]) => { - // @ts-expect-error untyped - return { ...acc, [k]: v.default }; - }, {}); + if (!isLess) continue; + // try to compile the less file, report any errors less.render(content, { lint: true, globalVars }).then().catch( - (err: any) => { + (err) => { log( err.message, - { - file: entry.relative, - startLine: err.line, - endLine: err.line, - content, - }, + { file, startLine: err.line, endLine: err.line, content }, "error", ); }, ); - lint(entry.absolute, flags.fix).then(({ results }) => { - results.sort( - (a, b) => (a.source ?? "").localeCompare(b.source ?? ""), - ).map((result) => { - result.warnings.map((warning) => { - const msg = warning.text?.replace( - new RegExp(`\\(?${warning.rule}\\)?`), - chalk.dim(`(${warning.rule})`), - ) ?? - "unspecified stylelint error"; - - const props = { - file: entry.relative, - startLine: warning.line, - endLine: warning.endLine, - startColumn: warning.column, - endColumn: warning.endColumn, - content, - } satisfies LoggerProps; - - log(msg, props, warning.severity); - }); - }); - }); - - [ - "catppuccin.user.css", - ...["latte", "frappe", "macchiato", "mocha", "catwalk"].map((f) => - `assets/${f}.webp` - ), - ].map(async (fp) => { - const filepath = join(repodir, fp); - await Deno.stat(join(repodir, fp)).catch(() => { - missingFiles.push(relative(REPO_ROOT, filepath)); - }); - }); + // advanced linting with stylelint + lint(entry, content, flags.fix); } -// only write summary if running in github actions -if (Deno.env.has("GITHUB_ACTIONS") && missingFiles.length !== 0) { - await core.summary.addHeading("Missing files").addList(missingFiles).write(); +// if any files are missing, cause the workflow to fail +if (await checkForMissingFiles() === false) { Deno.exit(1); } diff --git a/src/lint/metadata.ts b/src/lint/metadata.ts new file mode 100644 index 0000000000..09beb919ac --- /dev/null +++ b/src/lint/metadata.ts @@ -0,0 +1,81 @@ +// TODO: remove this once types for usercss-meta are available +// deno-lint-ignore-file no-explicit-any + +import chalk from "chalk"; +import usercssMeta from "usercss-meta"; +import { log } from "./logger.ts"; +import { sprintf } from "std/fmt/printf.ts"; +import type { WalkEntry } from "std/fs/mod.ts"; +import { relative } from "std/path/mod.ts"; +import { REPO_ROOT } from "@/deps.ts"; + +export const verifyMetadata = ( + entry: WalkEntry, + content: string, + repo: string, +): Promise<{ + globalVars: Record; + isLess: boolean; +}> => { + return new Promise((resolve, reject) => { + const assert = assertions(repo); + const file = relative(REPO_ROOT, entry.path); + + let metadata: Record = {}; + try { + metadata = usercssMeta.parse(content).metadata; + } catch (err) { + log(err, { file }, "error"); + reject(err); + } + + Object.entries(assert).forEach(([k, v]) => { + const defacto = metadata[k]; + if (defacto !== v) { + const line = content + .split("\n") + .findIndex((line) => line.includes(k)) + 1; + + const message = sprintf( + "Metadata %s should be %s but is %s", + chalk.bold(k), + chalk.green(v), + chalk.red(defacto), + ); + + log(message, { + file, + startLine: line !== 0 ? line : undefined, + content, + }, "warning"); + } + }); + + // parse the usercss variables to less global variables, e.g. + // `@var select lightFlavor "Light Flavor" ["latte:Latte*", "frappe:Frappé", "macchiato:Macchiato", "mocha:Mocha"]` + // gets parsed as + // `lightFlavor: "latte"` + + const globalVars = Object.entries<{ default: string }>(metadata.vars) + .reduce((acc, [k, v]) => { + return { ...acc, [k]: v.default }; + }, {}); + + resolve({ + globalVars, + isLess: metadata.preprocessor === assert.preprocessor, + }); + }); +}; + +const assertions = (repo: string) => { + const prefix = "https://github.com/catppuccin/userstyles"; + return { + namespace: `github.com/catppuccin/userstyles/styles/${repo}`, + author: "Catppuccin", + license: "MIT", + preprocessor: "less", + homepageURL: `${prefix}/tree/main/styles/${repo}`, + updateURL: `${prefix}/raw/main/styles/${repo}/catppuccin.user.css`, + }; +}; diff --git a/src/lint/stylelint.ts b/src/lint/stylelint.ts index 3a01fd2a3e..243823500a 100644 --- a/src/lint/stylelint.ts +++ b/src/lint/stylelint.ts @@ -1,10 +1,16 @@ import { deepMerge } from "std/collections/mod.ts"; +import chalk from "chalk"; import stylelint from "npm:stylelint"; import stylelintConfigStandard from "npm:stylelint-config-standard"; import stylelintConfigRecommended from "npm:stylelint-config-recommended"; import postcssLess from "npm:postcss-less"; +import { log } from "./logger.ts"; +import { relative } from "https://deno.land/std@0.150.0/path/mod.ts"; +import { REPO_ROOT } from "@/deps.ts"; +import { WalkEntry } from "std/fs/walk.ts"; + const config: stylelint.Config = { customSyntax: postcssLess, rules: { @@ -162,9 +168,32 @@ const base = deepMerge( { ...stylelintConfigStandard, extends: {} }, ); -export const lint = (files: string, fix: boolean) => +export const lint = (entry: WalkEntry, content: string, fix: boolean) => { + const file = relative(REPO_ROOT, entry.path); + stylelint.lint({ config: deepMerge(base, config), - files, + files: entry.path, fix, - }); + }) + .then(({ results }) => { + results.map((result) => { + result.warnings.map((warning) => { + // some cleanup for fancier logging, dims the rule name + const message = warning.text?.replace( + new RegExp(`\\(?${warning.rule}\\)?`), + chalk.dim(`(${warning.rule})`), + ) ?? "unspecified stylelint error"; + + log(message, { + file, + startLine: warning.line, + endLine: warning.endLine, + startColumn: warning.column, + endColumn: warning.endColumn, + content, + }, warning.severity); + }); + }); + }); +};