@pezkuwi/dev 0.86.1 → 0.86.3
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/cjs/packageInfo.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.packageInfo = void 0;
|
|
4
|
-
exports.packageInfo = { name: '@pezkuwi/dev', path: typeof __dirname === 'string' ? __dirname : 'auto', type: 'cjs', version: '0.86.
|
|
4
|
+
exports.packageInfo = { name: '@pezkuwi/dev', path: typeof __dirname === 'string' ? __dirname : 'auto', type: 'cjs', version: '0.86.3' };
|
package/config/eslint.js
CHANGED
|
@@ -24,6 +24,7 @@ import globals from 'globals';
|
|
|
24
24
|
|
|
25
25
|
import { overrideAll, overrideJs, overrideJsx, overrideSpec } from './eslint.rules.js';
|
|
26
26
|
import { standardRules } from './eslint.standard.js';
|
|
27
|
+
import { withoutContextualAssertions } from './eslint.typeAssertion.js';
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* eslint-plugin-header declares no options schema, and eslint 9+ rejects
|
|
@@ -93,7 +94,8 @@ export default [
|
|
|
93
94
|
},
|
|
94
95
|
plugins: {
|
|
95
96
|
'@stylistic': stylisticPlugin,
|
|
96
|
-
|
|
97
|
+
// see eslint.typeAssertion.js
|
|
98
|
+
'@typescript-eslint': withoutContextualAssertions(tsPlugin),
|
|
97
99
|
// eslint-plugin-header reports at the first token after the leading
|
|
98
100
|
// comments, so a generated file's /* eslint-disable */ covers it; the
|
|
99
101
|
// maintained fork reports at line 1 instead. The compat layer supplies the
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Copyright 2017-2026 @pezkuwi/dev authors & contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
const RULE = 'no-unnecessary-type-assertion';
|
|
5
|
+
const ASSERTIONS = ['TSAsExpression', 'TSTypeAssertion'];
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* typescript-eslint 8 added a second check to no-unnecessary-type-assertion:
|
|
9
|
+
* an `x as T` is reported as unnecessary when the place it is passed to would
|
|
10
|
+
* accept `x` as it is ("the receiver accepts the original type"), and the
|
|
11
|
+
* autofix deletes the assertion. That is unsound when the assertion also
|
|
12
|
+
* drives inference around it: in
|
|
13
|
+
*
|
|
14
|
+
* const { validators } = found || { validators: {} as ValPoints };
|
|
15
|
+
*
|
|
16
|
+
* deleting `as ValPoints` leaves `validators` typed `{}`, and every use of it
|
|
17
|
+
* after that is an unresolved type. It also deletes assertions kept on
|
|
18
|
+
* purpose for another environment's typings (a Ledger transport under
|
|
19
|
+
* esm.sh). Measured across the consumers before this was added: 45 such
|
|
20
|
+
* reports, the first of them breaking the types of api-derive.
|
|
21
|
+
*
|
|
22
|
+
* This keeps the rule as it was before that check: an assertion to the type
|
|
23
|
+
* the expression already has is still reported and fixed, and so are non-null
|
|
24
|
+
* assertions the receiver makes unnecessary. Only the contextual report on
|
|
25
|
+
* `as` / `<T>` assertions is dropped.
|
|
26
|
+
*
|
|
27
|
+
* @template {object} P
|
|
28
|
+
* @param {P} plugin the @typescript-eslint plugin
|
|
29
|
+
* @returns {P}
|
|
30
|
+
*/
|
|
31
|
+
export function withoutContextualAssertions (plugin) {
|
|
32
|
+
const rules = /** @type {Record<string, import('eslint').Rule.RuleModule>} */ (/** @type {{ rules: unknown }} */ (plugin).rules);
|
|
33
|
+
const rule = rules[RULE];
|
|
34
|
+
|
|
35
|
+
return /** @type {P} */ ({
|
|
36
|
+
...plugin,
|
|
37
|
+
rules: {
|
|
38
|
+
...rules,
|
|
39
|
+
[RULE]: {
|
|
40
|
+
...rule,
|
|
41
|
+
/** @param {import('eslint').Rule.RuleContext} context */
|
|
42
|
+
create (context) {
|
|
43
|
+
const filtered = Object.create(context, {
|
|
44
|
+
report: {
|
|
45
|
+
value: (/** @type {import('eslint').Rule.ReportDescriptor} */ descriptor) => {
|
|
46
|
+
if (
|
|
47
|
+
'messageId' in descriptor &&
|
|
48
|
+
descriptor.messageId === 'contextuallyUnnecessary' &&
|
|
49
|
+
'node' in descriptor &&
|
|
50
|
+
ASSERTIONS.includes(descriptor.node.type)
|
|
51
|
+
) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
context.report(descriptor);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return rule.create(filtered);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"sideEffects": false,
|
|
17
17
|
"type": "module",
|
|
18
|
-
"version": "0.86.
|
|
18
|
+
"version": "0.86.3",
|
|
19
19
|
"bin": {
|
|
20
20
|
"pezkuwi-ci-ghact-build": "./scripts/pezkuwi-ci-ghact-build.mjs",
|
|
21
21
|
"pezkuwi-ci-ghact-docs": "./scripts/pezkuwi-ci-ghact-docs.mjs",
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"./config/eslint": "./config/eslint.js",
|
|
66
66
|
"./config/eslint.rules": "./config/eslint.rules.js",
|
|
67
67
|
"./config/eslint.standard": "./config/eslint.standard.js",
|
|
68
|
+
"./config/eslint.typeAssertion": "./config/eslint.typeAssertion.js",
|
|
68
69
|
"./config/prettier.cjs": "./config/prettier.cjs",
|
|
69
70
|
"./config/prettier": "./config/prettier.cjs",
|
|
70
71
|
"./config/rollup": "./config/rollup.js",
|
|
@@ -288,8 +289,8 @@
|
|
|
288
289
|
"dependencies": {
|
|
289
290
|
"@eslint/compat": "^2.1.1",
|
|
290
291
|
"@eslint/js": "^10.0.1",
|
|
291
|
-
"@pezkuwi/dev-test": "^0.86.
|
|
292
|
-
"@pezkuwi/dev-ts": "^0.86.
|
|
292
|
+
"@pezkuwi/dev-test": "^0.86.3",
|
|
293
|
+
"@pezkuwi/dev-ts": "^0.86.3",
|
|
293
294
|
"@rollup/plugin-alias": "^5.1.1",
|
|
294
295
|
"@rollup/plugin-commonjs": "^29.0.3",
|
|
295
296
|
"@rollup/plugin-dynamic-import-vars": "^2.1.5",
|
package/packageInfo.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const packageInfo = { name: '@pezkuwi/dev', path: (import.meta && import.meta.url) ? new URL(import.meta.url).pathname.substring(0, new URL(import.meta.url).pathname.lastIndexOf('/') + 1) : 'auto', type: 'esm', version: '0.86.
|
|
1
|
+
export const packageInfo = { name: '@pezkuwi/dev', path: (import.meta && import.meta.url) ? new URL(import.meta.url).pathname.substring(0, new URL(import.meta.url).pathname.lastIndexOf('/') + 1) : 'auto', type: 'esm', version: '0.86.3' };
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
// pezkuwi-dev-migrate-eslint10 --check # report, change nothing (exit 1 if anything would change)
|
|
15
15
|
//
|
|
16
16
|
// It also rewrites such comments inside string literals, which is how code
|
|
17
|
-
// generators emit them
|
|
17
|
+
// generators emit them, and the rule keys of the repository's own
|
|
18
|
+
// eslint.config.* ('import/extensions': 'off'). A rule that became several
|
|
19
|
+
// is reported for a hand edit there, and the tool then exits 1.
|
|
18
20
|
|
|
19
21
|
import stylisticPlugin from '@stylistic/eslint-plugin';
|
|
20
22
|
import { builtinRules } from 'eslint/use-at-your-own-risk';
|
|
@@ -96,6 +98,38 @@ const files = execFileSync('git', ['ls-files', '-z', '--', '*.ts', '*.tsx', '*.j
|
|
|
96
98
|
const check = process.argv.includes('--check');
|
|
97
99
|
let changedFiles = 0;
|
|
98
100
|
let changedComments = 0;
|
|
101
|
+
let changedKeys = 0;
|
|
102
|
+
/** @type {string[]} */
|
|
103
|
+
const manual = [];
|
|
104
|
+
|
|
105
|
+
// Rule keys in a repository's own eslint config ('import/extensions': 'off'),
|
|
106
|
+
// quoted or not. Only in eslint.config.* files, where such a key is a rule.
|
|
107
|
+
const CONFIG_FILE = /(^|\/)eslint\.config\.[cm]?[jt]s$/;
|
|
108
|
+
const CONFIG_KEY = /(^|[{,\s])(['"]?)([@a-z][\w@/-]*)\2(\s*:)/g;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @param {string} file
|
|
112
|
+
* @param {string} src
|
|
113
|
+
* @returns {string}
|
|
114
|
+
*/
|
|
115
|
+
function renameConfigKeys (file, src) {
|
|
116
|
+
return src.replace(CONFIG_KEY, (/** @type {string} */ all, /** @type {string} */ pre, /** @type {string} */ _quote, /** @type {string} */ name, /** @type {string} */ colon) => {
|
|
117
|
+
const next = rename(name);
|
|
118
|
+
|
|
119
|
+
if (next.length === 1 && next[0] === name) {
|
|
120
|
+
return all;
|
|
121
|
+
} else if (next.length !== 1) {
|
|
122
|
+
// one rule became several: the value has to be repeated for each, by hand
|
|
123
|
+
manual.push(`${file}: '${name}' is now ${next.join(', ')}`);
|
|
124
|
+
|
|
125
|
+
return all;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
changedKeys++;
|
|
129
|
+
|
|
130
|
+
return `${pre}'${next[0]}'${colon}`;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
99
133
|
|
|
100
134
|
for (const file of files) {
|
|
101
135
|
const src = fs.readFileSync(file, 'utf-8');
|
|
@@ -116,19 +150,27 @@ for (const file of files) {
|
|
|
116
150
|
return `${kind}${gap}${next.join(', ')}${tail}`;
|
|
117
151
|
});
|
|
118
152
|
|
|
119
|
-
|
|
153
|
+
const outKeys = CONFIG_FILE.test(file)
|
|
154
|
+
? renameConfigKeys(file, out)
|
|
155
|
+
: out;
|
|
156
|
+
|
|
157
|
+
if (outKeys !== src) {
|
|
120
158
|
changedFiles++;
|
|
121
159
|
|
|
122
160
|
if (check) {
|
|
123
161
|
console.log(`would change: ${file}`);
|
|
124
162
|
} else {
|
|
125
|
-
fs.writeFileSync(file,
|
|
163
|
+
fs.writeFileSync(file, outKeys);
|
|
126
164
|
}
|
|
127
165
|
}
|
|
128
166
|
}
|
|
129
167
|
|
|
130
|
-
|
|
168
|
+
for (const line of manual) {
|
|
169
|
+
console.log(`by hand: ${line}`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
console.log(`${check ? 'would rewrite' : 'rewrote'} ${changedComments} directive(s) and ${changedKeys} config key(s) in ${changedFiles} file(s)`);
|
|
131
173
|
|
|
132
|
-
if (check && changedFiles) {
|
|
174
|
+
if ((check && changedFiles) || manual.length) {
|
|
133
175
|
process.exit(1);
|
|
134
176
|
}
|