@plumeria/eslint-plugin 19.9.1 → 19.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -38
- package/bin/oxlint.js +18 -12
- package/dist/guard.d.ts +10 -0
- package/dist/guard.js +104 -0
- package/dist/index.js +1 -0
- package/oxlint.json +2 -0
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@ Below are the available rules and the recommended configuration.
|
|
|
8
8
|
The `plugin:@plumeria/recommended` config enables the following:
|
|
9
9
|
|
|
10
10
|
- `@plumeria/custom-props-require-import`: **error**
|
|
11
|
+
- `@plumeria/expand-border-shorthands`: **warn**
|
|
11
12
|
- `@plumeria/no-combinator`: **error**
|
|
12
13
|
- `@plumeria/no-destructure`: **error**
|
|
13
14
|
- `@plumeria/no-inline-object`: **error**
|
|
@@ -82,6 +83,27 @@ the import.
|
|
|
82
83
|
|
|
83
84
|
Accepts `{ styleProp }`; see [Configuring the styling prop](#configuring-the-styling-prop).
|
|
84
85
|
|
|
86
|
+
### expand-border-shorthands
|
|
87
|
+
|
|
88
|
+
Expands a border shorthand that bundles a width, a style and a color —
|
|
89
|
+
`border`, `borderBlock`, `borderInline`, and the eight edge forms — into the
|
|
90
|
+
three declarations it stands for. Those bundles are the only properties left
|
|
91
|
+
that cross an axis shorthand without either containing the other, so expanding
|
|
92
|
+
them turns the last unrankable pairs into ordinary shorthand-to-longhand ones.
|
|
93
|
+
|
|
94
|
+
Fixable. A value it cannot split, such as `var(--edge)` or `inherit`, is
|
|
95
|
+
reported without a fix: leaving it silent would let the expanded declarations
|
|
96
|
+
elsewhere outrank it.
|
|
97
|
+
|
|
98
|
+
```js
|
|
99
|
+
borderTop: '1px solid red'
|
|
100
|
+
// becomes
|
|
101
|
+
borderTopWidth: '1px', borderTopStyle: 'solid', borderTopColor: 'red'
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
A shorthand resets what it omits, so `borderBlock: 'solid'` expands with
|
|
105
|
+
`medium` and `currentcolor` written out.
|
|
106
|
+
|
|
85
107
|
### no-combinator
|
|
86
108
|
|
|
87
109
|
Disallow combinators `>`, `+`, `~` and descendant combinator (space) unless inside functional pseudo-classes.
|
|
@@ -176,8 +198,8 @@ Validates at-rules inside `css.create()`. It accepts `@media`, `@container`, `@s
|
|
|
176
198
|
|
|
177
199
|
## Optional rules
|
|
178
200
|
|
|
179
|
-
These rules are not enabled by `plumeria.configs.recommended`. Enable
|
|
180
|
-
policy
|
|
201
|
+
These rules are not enabled by `plumeria.configs.recommended`. Enable the
|
|
202
|
+
spelling policy that fits the project:
|
|
181
203
|
|
|
182
204
|
```js
|
|
183
205
|
export default [
|
|
@@ -185,33 +207,11 @@ export default [
|
|
|
185
207
|
{
|
|
186
208
|
rules: {
|
|
187
209
|
'@plumeria/no-logical-properties': 'warn',
|
|
188
|
-
'@plumeria/expand-border-shorthands': 'warn',
|
|
189
210
|
},
|
|
190
211
|
},
|
|
191
212
|
];
|
|
192
213
|
```
|
|
193
214
|
|
|
194
|
-
### expand-border-shorthands
|
|
195
|
-
|
|
196
|
-
Expands a border shorthand that bundles a width, a style and a color —
|
|
197
|
-
`border`, `borderBlock`, `borderInline`, and the eight edge forms — into the
|
|
198
|
-
three declarations it stands for. Those bundles are the only properties left
|
|
199
|
-
that cross an axis shorthand without either containing the other, so expanding
|
|
200
|
-
them turns the last unrankable pairs into ordinary shorthand-to-longhand ones.
|
|
201
|
-
|
|
202
|
-
Fixable. A value it cannot split, such as `var(--edge)` or `inherit`, is
|
|
203
|
-
reported without a fix: leaving it silent would let the expanded declarations
|
|
204
|
-
elsewhere outrank it.
|
|
205
|
-
|
|
206
|
-
```js
|
|
207
|
-
borderTop: '1px solid red'
|
|
208
|
-
// becomes
|
|
209
|
-
borderTopWidth: '1px', borderTopStyle: 'solid', borderTopColor: 'red'
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
A shorthand resets what it omits, so `borderBlock: 'solid'` expands with
|
|
213
|
-
`medium` and `currentcolor` written out.
|
|
214
|
-
|
|
215
215
|
### no-physical-properties / no-logical-properties
|
|
216
216
|
|
|
217
217
|
Disallow one of the two names a property can carry, so a project writes edges
|
|
@@ -228,19 +228,24 @@ appears under one spelling only can never meet its other spelling on an element.
|
|
|
228
228
|
A shorthand with no single counterpart, such as `borderBlockWidth`, is outside
|
|
229
229
|
either rule and stays reported.
|
|
230
230
|
|
|
231
|
+
The bundler plugins turn the matching rule on in the build lint as well:
|
|
232
|
+
`withoutPhysicalProperties` runs `no-physical-properties`, and
|
|
233
|
+
`withoutLogicalProperties` runs `no-logical-properties`, `{ sizes }` included.
|
|
234
|
+
|
|
231
235
|
## CLI (plumerialint)
|
|
232
236
|
|
|
233
237
|
This package provides a CLI command, `plumerialint`, as a convenient way
|
|
234
238
|
to run Plumeria's custom ESLint rules.
|
|
235
239
|
|
|
236
|
-
It
|
|
240
|
+
It runs `oxlint`, which this package depends on, for fast linting with code
|
|
241
|
+
snippets in output, so oxlint needs no separate install.
|
|
237
242
|
|
|
238
243
|
### Installation
|
|
239
244
|
|
|
240
245
|
```bash
|
|
241
|
-
npm install -D @plumeria/eslint-plugin
|
|
246
|
+
npm install -D @plumeria/eslint-plugin
|
|
242
247
|
# or
|
|
243
|
-
pnpm add -D @plumeria/eslint-plugin
|
|
248
|
+
pnpm add -D @plumeria/eslint-plugin
|
|
244
249
|
```
|
|
245
250
|
|
|
246
251
|
### Usage
|
|
@@ -252,16 +257,6 @@ plumerialint
|
|
|
252
257
|
The process exits with a non-zero status code if any errors or warnings are found,
|
|
253
258
|
making it suitable for use in CI and build pipelines.
|
|
254
259
|
|
|
255
|
-
Example usage in `package.json`:
|
|
256
|
-
|
|
257
|
-
```json
|
|
258
|
-
{
|
|
259
|
-
"scripts": {
|
|
260
|
-
"lint": "plumerialint"
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
```
|
|
264
|
-
|
|
265
260
|
### Aborting Builds on Lint Errors (Parallel Pipeline)
|
|
266
261
|
|
|
267
262
|
You can run `plumerialint` in parallel with your build command (e.g. `next build` or `vite build`) using the `--` separator:
|
|
@@ -276,4 +271,4 @@ You can run `plumerialint` in parallel with your build command (e.g. `next build
|
|
|
276
271
|
|
|
277
272
|
If `plumerialint` detects any styling errors or warnings, it will print the diagnostics, kill the build process immediately, and exit with a non-zero code. This avoids compiling when styling validation fails.
|
|
278
273
|
|
|
279
|
-
|
|
274
|
+
With `@plumeria/next-plugin` and `@plumeria/unplugin` (except on esbuild and Bun), this lint is integrated into the build by default, so it needs no setup. Pass `lint: false` to the plugin to build without it.
|
package/bin/oxlint.js
CHANGED
|
@@ -4,6 +4,11 @@ const { spawn } = require('child_process');
|
|
|
4
4
|
const process = require('process');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const oxlintConfig = path.join(__dirname, '..', 'oxlint.json');
|
|
7
|
+
const oxlintBin = path.join(
|
|
8
|
+
path.dirname(require.resolve('oxlint/package.json')),
|
|
9
|
+
'bin',
|
|
10
|
+
'oxlint',
|
|
11
|
+
);
|
|
7
12
|
|
|
8
13
|
const doubleDashIndex = process.argv.indexOf('--');
|
|
9
14
|
let oxlintExtraArgs = [];
|
|
@@ -20,22 +25,22 @@ if (doubleDashIndex !== -1) {
|
|
|
20
25
|
oxlintExtraArgs = process.argv.slice(2);
|
|
21
26
|
}
|
|
22
27
|
|
|
23
|
-
const oxlintArgs = [
|
|
28
|
+
const oxlintArgs = [
|
|
29
|
+
oxlintBin,
|
|
30
|
+
'-c',
|
|
31
|
+
oxlintConfig,
|
|
32
|
+
'--deny-warnings',
|
|
33
|
+
'--no-error-on-unmatched-pattern',
|
|
34
|
+
...oxlintExtraArgs,
|
|
35
|
+
];
|
|
24
36
|
|
|
25
37
|
function handleOxlintError(err) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
console.error('➡︎ plumerialint uses oxlint.');
|
|
29
|
-
console.error('✔ please install oxlint.\n');
|
|
30
|
-
process.exit(1);
|
|
31
|
-
} else {
|
|
32
|
-
console.error('Error running oxlint:', err.message);
|
|
33
|
-
process.exit(1);
|
|
34
|
-
}
|
|
38
|
+
console.error('Error running oxlint:', err.message);
|
|
39
|
+
process.exit(1);
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
if (!buildCommand) {
|
|
38
|
-
const child = spawn(
|
|
43
|
+
const child = spawn(process.execPath, oxlintArgs, { stdio: 'inherit' });
|
|
39
44
|
child.on('error', handleOxlintError);
|
|
40
45
|
child.on('close', (code) => {
|
|
41
46
|
process.exit(code || 0);
|
|
@@ -47,7 +52,7 @@ if (!buildCommand) {
|
|
|
47
52
|
let buildCode = null;
|
|
48
53
|
let aborted = false;
|
|
49
54
|
|
|
50
|
-
const oxlintChild = spawn(
|
|
55
|
+
const oxlintChild = spawn(process.execPath, oxlintArgs, { stdio: 'inherit' });
|
|
51
56
|
|
|
52
57
|
const fullBuildCommand =
|
|
53
58
|
buildArgs.length > 0
|
|
@@ -57,6 +62,7 @@ if (!buildCommand) {
|
|
|
57
62
|
const buildChild = spawn(fullBuildCommand, {
|
|
58
63
|
stdio: 'inherit',
|
|
59
64
|
shell: true,
|
|
65
|
+
env: { ...process.env, PLUMERIA_LINT_GUARD: '1' },
|
|
60
66
|
});
|
|
61
67
|
|
|
62
68
|
function abort(exitCode, failedSource) {
|
package/dist/guard.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type Spelling = boolean | {
|
|
2
|
+
sizes?: boolean;
|
|
3
|
+
} | undefined;
|
|
4
|
+
interface SpellingOptions {
|
|
5
|
+
withoutLogicalProperties?: Spelling;
|
|
6
|
+
withoutPhysicalProperties?: Spelling;
|
|
7
|
+
}
|
|
8
|
+
export declare function spellingRules(options: SpellingOptions): Record<string, unknown>;
|
|
9
|
+
export declare function startLintGuard(rules?: Record<string, unknown>): boolean;
|
|
10
|
+
export {};
|
package/dist/guard.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.spellingRules = spellingRules;
|
|
37
|
+
exports.startLintGuard = startLintGuard;
|
|
38
|
+
const child_process_1 = require("child_process");
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const os = __importStar(require("os"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const GUARD_ENV = 'PLUMERIA_LINT_GUARD';
|
|
43
|
+
const BASE_CONFIG = path.join(__dirname, '..', 'oxlint.json');
|
|
44
|
+
function spellingRule(spelling) {
|
|
45
|
+
if (!spelling)
|
|
46
|
+
return undefined;
|
|
47
|
+
return typeof spelling === 'object' && spelling.sizes
|
|
48
|
+
? ['error', { sizes: true }]
|
|
49
|
+
: 'error';
|
|
50
|
+
}
|
|
51
|
+
function spellingRules(options) {
|
|
52
|
+
const rules = {};
|
|
53
|
+
const logical = spellingRule(options.withoutLogicalProperties);
|
|
54
|
+
const physical = spellingRule(options.withoutPhysicalProperties);
|
|
55
|
+
if (logical)
|
|
56
|
+
rules['@plumeria/no-logical-properties'] = logical;
|
|
57
|
+
if (physical)
|
|
58
|
+
rules['@plumeria/no-physical-properties'] = physical;
|
|
59
|
+
return rules;
|
|
60
|
+
}
|
|
61
|
+
function lintConfig(rules) {
|
|
62
|
+
if (Object.keys(rules).length === 0)
|
|
63
|
+
return BASE_CONFIG;
|
|
64
|
+
const file = path.join(os.tmpdir(), `plumeria-oxlint-${process.pid}.json`);
|
|
65
|
+
fs.writeFileSync(file, JSON.stringify({ extends: [BASE_CONFIG], rules }));
|
|
66
|
+
return file;
|
|
67
|
+
}
|
|
68
|
+
function startLintGuard(rules = {}) {
|
|
69
|
+
if (process.env[GUARD_ENV])
|
|
70
|
+
return false;
|
|
71
|
+
process.env[GUARD_ENV] = '1';
|
|
72
|
+
const config = lintConfig(rules);
|
|
73
|
+
const child = (0, child_process_1.spawn)(process.execPath, [
|
|
74
|
+
path.join(path.dirname(require.resolve('oxlint/package.json')), 'bin', 'oxlint'),
|
|
75
|
+
'-c',
|
|
76
|
+
config,
|
|
77
|
+
'--deny-warnings',
|
|
78
|
+
'--no-error-on-unmatched-pattern',
|
|
79
|
+
], { stdio: 'inherit' });
|
|
80
|
+
const exit = process.exit.bind(process);
|
|
81
|
+
let lintCode = null;
|
|
82
|
+
let pendingCode = null;
|
|
83
|
+
child.on('error', (error) => {
|
|
84
|
+
console.error(`\n✖ [plumeria] Could not run oxlint: ${error.message}`);
|
|
85
|
+
exit(1);
|
|
86
|
+
});
|
|
87
|
+
child.on('close', (code) => {
|
|
88
|
+
if (config !== BASE_CONFIG)
|
|
89
|
+
fs.rmSync(config, { force: true });
|
|
90
|
+
lintCode = code ?? 1;
|
|
91
|
+
if (lintCode !== 0) {
|
|
92
|
+
console.error('\n✖ [plumeria] Linting failed. Aborting build...');
|
|
93
|
+
return exit(lintCode);
|
|
94
|
+
}
|
|
95
|
+
if (pendingCode !== null)
|
|
96
|
+
exit(pendingCode);
|
|
97
|
+
});
|
|
98
|
+
process.exit = ((code) => {
|
|
99
|
+
if (lintCode !== null)
|
|
100
|
+
return exit(code);
|
|
101
|
+
pendingCode = code;
|
|
102
|
+
});
|
|
103
|
+
return true;
|
|
104
|
+
}
|
package/dist/index.js
CHANGED
package/oxlint.json
CHANGED
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
}
|
|
7
7
|
],
|
|
8
8
|
"plugins": [],
|
|
9
|
+
"categories": { "correctness": "off" },
|
|
9
10
|
"ignorePatterns": ["**/*.svelte", "**/*.vue"],
|
|
10
11
|
|
|
11
12
|
"rules": {
|
|
12
13
|
"@plumeria/custom-props-require-import": "error",
|
|
14
|
+
"@plumeria/expand-border-shorthands": "warn",
|
|
13
15
|
"@plumeria/no-combinator": "error",
|
|
14
16
|
"@plumeria/no-destructure": "error",
|
|
15
17
|
"@plumeria/no-inline-object": "error",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plumeria/eslint-plugin",
|
|
3
|
-
"version": "19.
|
|
3
|
+
"version": "19.10.1",
|
|
4
4
|
"description": "Plumeria ESLint plugin",
|
|
5
5
|
"author": "Refirst 11",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
"types": "./dist/index.d.ts",
|
|
30
30
|
"default": "./dist/index.js"
|
|
31
31
|
},
|
|
32
|
+
"./guard": {
|
|
33
|
+
"types": "./dist/guard.d.ts",
|
|
34
|
+
"default": "./dist/guard.js"
|
|
35
|
+
},
|
|
32
36
|
"./oxlint-plugin": "./oxlint-plugin.js"
|
|
33
37
|
},
|
|
34
38
|
"files": [
|
|
@@ -53,8 +57,9 @@
|
|
|
53
57
|
},
|
|
54
58
|
"dependencies": {
|
|
55
59
|
"known-css-properties": "^0.37.0",
|
|
60
|
+
"oxlint": "1.87.0",
|
|
56
61
|
"zss-engine": "2.9.1",
|
|
57
|
-
"@plumeria/compiler": "19.
|
|
62
|
+
"@plumeria/compiler": "19.10.1"
|
|
58
63
|
},
|
|
59
64
|
"scripts": {
|
|
60
65
|
"build": "rimraf dist && pnpm cjs",
|