From 9effff8bcf5d721d1d72087bc677f2f383365d31 Mon Sep 17 00:00:00 2001 From: Damian Krzeminski Date: Fri, 6 Jun 2025 09:21:54 -0600 Subject: [PATCH 1/2] use `biome` as a linter and formatter --- .editorconfig | 15 +++++++++++ .jshintrc | 9 ------- Makefile | 13 ++++++---- biome.json | 49 +++++++++++++++++++++++++++++++++++ lib/argv.js | 13 +++++----- lib/run.js | 9 ++----- package.json | 2 +- test/argv.js | 26 +++++++++---------- test/cmd.js | 41 +++++++++++++++-------------- test/fixtures/dummy-plugin.js | 2 +- 10 files changed, 117 insertions(+), 62 deletions(-) create mode 100644 .editorconfig delete mode 100644 .jshintrc create mode 100644 biome.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..86e884b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 7f6c17d..0000000 --- a/.jshintrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "node": true, - "undef": true, - "unused": true, - "laxbreak": true, - "laxcomma": true, - "proto": true, - "esversion": 11 -} diff --git a/Makefile b/Makefile index 7a61935..25dd41a 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,15 @@ check: lint test lint: - ./node_modules/.bin/jshint *.js lib test bin/postcss + ./node_modules/.bin/biome ci + +format: + ./node_modules/.bin/biome check --fix test: - node --test test/*.js + node --test $(TEST_OPTS) test/*.js -clean: - rm -rf test/_build +test-cov: TEST_OPTS := --experimental-test-coverage +test-cov: test -.PHONY: check clean lint test +.PHONY: check format lint test test-cov diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..a30981c --- /dev/null +++ b/biome.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "organizeImports": { + "enabled": true + }, + "vcs": { + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": true, + "ignore": ["package.json", "test/fixtures", "test/ref"] + }, + "formatter": { + "enabled": true, + "useEditorconfig": true, + "lineWidth": 120 + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "none", + "arrowParentheses": "asNeeded" + } + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "correctness": { + "noUndeclaredVariables": "error", + "noUnusedVariables": "error" + }, + "complexity": { + "noForEach": "off", + "useLiteralKeys": "off" + }, + "style": { + "noParameterAssign": "off", + "useTemplate": "off" + }, + "performance": { + "noDelete": "off" + }, + "suspicious": { + "noAssignInExpressions": "off" + } + } + } +} diff --git a/lib/argv.js b/lib/argv.js index 75cf877..085aa2e 100644 --- a/lib/argv.js +++ b/lib/argv.js @@ -12,9 +12,9 @@ const parserConfig = { parser: 'p', stringifier: 't', version: 'v', - help: 'h', + help: 'h' }, - array: [ 'use' ], + array: ['use'], config: 'config', @@ -24,19 +24,19 @@ const parserConfig = { output: 1, syntax: 1, parser: 1, - stringifier: 1, + stringifier: 1 }, boolean: ['version', 'help'], coerce: { - map: v => v === 'file' ? { inline: false } : v + map: v => (v === 'file' ? { inline: false } : v) } }; function version() { const { version } = require('postcss/package.json'); - return `postcss version: ${ version }`; + return `postcss version: ${version}`; } function usage() { @@ -66,7 +66,7 @@ postcss --use autoprefixer --autoprefixer.browsers "> 5%" -o screen.css screen.c } function parse(args = process.argv.slice(2)) { - let argv = yargsParser(args, parserConfig); + const argv = yargsParser(args, parserConfig); if (argv.version) { console.log(version()); @@ -92,4 +92,3 @@ function parse(args = process.argv.slice(2)) { return argv; } - diff --git a/lib/run.js b/lib/run.js index 1e257f0..361bdac 100644 --- a/lib/run.js +++ b/lib/run.js @@ -1,10 +1,9 @@ -const { readFile, writeFile } = require('fs').promises; +const { readFile, writeFile } = require('node:fs/promises'); const postcss = require('postcss'); module.exports = run; async function run(argv) { - // load and configure plugin array const plugins = argv.use.map(name => { let plugin = require(name); @@ -16,11 +15,7 @@ async function run(argv) { return plugin; }); - const commonOptions = [ - 'syntax', - 'parser', - 'stringifier' - ].reduce((cso, opt) => { + const commonOptions = ['syntax', 'parser', 'stringifier'].reduce((cso, opt) => { if (argv[opt]) { cso[opt] = require(argv[opt]); } diff --git a/package.json b/package.json index b25b09a..1b889b9 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "postcss": "~5 || ~6 || ~7 || ~8" }, "devDependencies": { - "@pirxpilot/jshint": "~3", + "@biomejs/biome": "^1.9.4", "postcss": "~8", "postcss-url": "~10" }, diff --git a/test/argv.js b/test/argv.js index 72a73da..b97308c 100644 --- a/test/argv.js +++ b/test/argv.js @@ -7,19 +7,19 @@ function _(strings) { return strings[0].trim().split(/\s+/); } -test('single plugin', function(t) { +test('single plugin', t => { t.plan(5); const opts = argv(_`--use autoprefixer -o out.css in.css`); - t.assert.deepEqual(opts.use, [ 'autoprefixer' ]); + t.assert.deepEqual(opts.use, ['autoprefixer']); t.assert.equal(opts.output, 'out.css'); - t.assert.deepEqual(opts._, [ 'in.css' ]); + t.assert.deepEqual(opts._, ['in.css']); t.assert.equal(opts.version, undefined, 'should not have version'); t.assert.equal(opts.help, undefined, 'should not have tape'); }); -test('syntax', function(t) { +test('syntax', t => { t.plan(1); const opts = argv(_` @@ -32,7 +32,7 @@ test('syntax', function(t) { t.assert.equal(opts.syntax, 'mysyntax'); }); -test('parser', function(t) { +test('parser', t => { t.plan(1); const opts = argv(_` @@ -45,7 +45,7 @@ test('parser', function(t) { t.assert.equal(opts.parser, 'myparser'); }); -test('stringifier', function(t) { +test('stringifier', t => { t.plan(1); const opts = argv(_` @@ -58,17 +58,17 @@ test('stringifier', function(t) { t.assert.equal(opts.stringifier, 'mystringifier'); }); -test('config .json', function(t) { +test('config .json', t => { t.plan(3); const opts = argv(_`--config test/fixtures/config-all.json in.css`); - t.assert.deepEqual(opts.use, [ 'postcss-url' ]); + t.assert.deepEqual(opts.use, ['postcss-url']); t.assert.equal(opts.output, 'test/build/config-all.css'); t.assert.deepEqual(opts['postcss-url'], { url: 'inline' }); }); -test('config .js', function(t) { +test('config .js', t => { t.plan(4); const opts = argv(_` @@ -78,14 +78,14 @@ test('config .js', function(t) { in.css `); - t.assert.deepEqual(opts.use, [ 'postcss-url' ]); + t.assert.deepEqual(opts.use, ['postcss-url']); t.assert.equal(opts.output, 'out.css'); t.assert.ok(opts['postcss-url'], 'opts should have `postcss-url` property'); t.assert.equal(typeof opts['postcss-url'].url, 'function'); }); -test('multiple plugins with options', function(t) { +test('multiple plugins with options', t => { t.plan(6); const opts = argv(_` @@ -95,9 +95,9 @@ test('multiple plugins with options', function(t) { --output out.css in.css `); - t.assert.deepEqual(opts.use, [ 'postcss-url', 'autoprefixer', 'cssnano' ]); + t.assert.deepEqual(opts.use, ['postcss-url', 'autoprefixer', 'cssnano']); t.assert.deepEqual(opts.output, 'out.css'); - t.assert.deepEqual(opts._, [ 'in.css' ]); + t.assert.deepEqual(opts._, ['in.css']); t.assert.deepEqual(opts['postcss-url'], { url: 'rebase', assetPath: '/temp/example' }); t.assert.deepEqual(opts.autoprefixer, { browsers: '>5%' }); diff --git a/test/cmd.js b/test/cmd.js index 4cad481..7ac5c77 100644 --- a/test/cmd.js +++ b/test/cmd.js @@ -10,9 +10,10 @@ const exec = promisify(execCB); function c(strs) { return strs - .map(s => s - .replace('postcss', resolve(__dirname, '../bin/postcss')) - .replace(/fixtures|ref|_build/g, p => resolve(__dirname, p)) + .map(s => + s + .replace('postcss', resolve(__dirname, '../bin/postcss')) + .replace(/fixtures|ref|_build/g, p => resolve(__dirname, p)) ) .join(''); } @@ -21,17 +22,16 @@ function read(path) { return readFile(path, 'utf-8'); } -test('cmd', async function (t) { - - t.before(function () { +test('cmd', async t => { + t.before(() => { return mkdir(c`_build`, { recursive: true }); }); - t.after(function () { + t.after(() => { return rm(c`_build`, { recursive: true }); }); - await t.test('help', async function () { + await t.test('help', async () => { const { stdout, stderr } = await exec(c`postcss --help`); assert.equal(stderr, ''); assert.ok(stdout.includes('Usage:'), 'help needs to include Usage'); @@ -39,13 +39,13 @@ test('cmd', async function (t) { assert.ok(stdout.includes('Examples:'), 'help needs to include Examples'); }); - await t.test('version', async function () { + await t.test('version', async () => { const { stdout, stderr } = await exec(c`postcss --version`); assert.equal(stderr, ''); assert.match(stdout, /postcss version: \d+\.\d+\.\d+/, 'version of postcss is displayed'); }); - await t.test('warning', async function () { + await t.test('warning', async () => { const cmd = c` NODE_PATH=fixtures postcss --use dummy-plugin -o _build/warning.css fixtures/in-warning.css `; @@ -54,7 +54,7 @@ test('cmd', async function (t) { assert.equal(stdout, '', 'should be empty'); }); - await t.test('error', async function () { + await t.test('error', async () => { const cmd = c` NO_COLOR=1 \ NODE_PATH=fixtures \ @@ -66,15 +66,18 @@ test('cmd', async function (t) { const { code, stderr, stdout } = await exec(cmd).catch(e => e); assert.equal(code, 1); assert.equal(stdout, '', 'should be empty'); - assert.equal(stderr, c`dummy-plugin: fixtures/in-force-error.css:1:1: Dummy error > 1 | a { + assert.equal( + stderr, + c`dummy-plugin: fixtures/in-force-error.css:1:1: Dummy error > 1 | a { | ^ 2 | background: url(image.png); 3 | display: flex; -` - , 'should display error'); +`, + 'should display error' + ); }); - await t.test('source-maps-file', async function () { + await t.test('source-maps-file', async () => { const cmd = c` postcss -u postcss-url --postcss-url.url=rebase --map file -o _build/source-maps-file.css fixtures/in.css `; @@ -89,7 +92,6 @@ test('cmd', async function (t) { const outputMap = await read(c`_build/source-maps-file.css.map`); assert.equal(outputMap, expectedMap, 'source map is emitted to a file'); - }); await cliTest('opts', c`postcss --use -u postcss-url --postcss-url.url=rebase`); @@ -104,12 +106,14 @@ test('cmd', async function (t) { await cliTest('js-config-all', c`postcss -c fixtures/config-all.js`); - async function cliTest(name, cmd, + async function cliTest( + name, + cmd, inpath = c`fixtures/in.css`, outpath = c`_build/` + `${name}.css`, refpath = outpath.replace('_build', 'ref') ) { - await t.test(name, async function () { + await t.test(name, async () => { const expected = await read(refpath); const { stdout, stderr } = await exec(`${cmd} -o ${outpath} ${inpath}`); assert.equal(stderr, '', 'stderr should be empty'); @@ -119,4 +123,3 @@ test('cmd', async function (t) { }); } }); - diff --git a/test/fixtures/dummy-plugin.js b/test/fixtures/dummy-plugin.js index e576496..bfaf7e1 100644 --- a/test/fixtures/dummy-plugin.js +++ b/test/fixtures/dummy-plugin.js @@ -1,4 +1,4 @@ -module.exports = function() { +module.exports = () => { return { postcssPlugin: 'dummy-plugin', Rule: function (rule, { result }) { From fa29e933112427b548976c0a4d46f342113afe2c Mon Sep 17 00:00:00 2001 From: Damian Krzeminski Date: Fri, 6 Jun 2025 09:35:06 -0600 Subject: [PATCH 2/2] Release 4.0.4 --- History.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index e5e4c78..716417b 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,9 @@ +4.0.4 / 2025-06-06 +================== + + * use `biome` as a linter and formatter + 4.0.3 / 2024-12-25 ================== diff --git a/package.json b/package.json index 1b889b9..acbaeb5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "postcss-cli-simple", - "version": "4.0.3", + "version": "4.0.4", "description": "simple CLI for postcss", "main": "index.js", "bin": {