@pezkuwi/dev 0.86.0 → 0.86.2

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.
@@ -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.0' };
4
+ exports.packageInfo = { name: '@pezkuwi/dev', path: typeof __dirname === 'string' ? __dirname : 'auto', type: 'cjs', version: '0.86.2' };
package/package.json CHANGED
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "sideEffects": false,
17
17
  "type": "module",
18
- "version": "0.86.0",
18
+ "version": "0.86.2",
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",
@@ -28,6 +28,7 @@
28
28
  "pezkuwi-dev-copy-dir": "./scripts/pezkuwi-dev-copy-dir.mjs",
29
29
  "pezkuwi-dev-copy-to": "./scripts/pezkuwi-dev-copy-to.mjs",
30
30
  "pezkuwi-dev-deno-map": "./scripts/pezkuwi-dev-deno-map.mjs",
31
+ "pezkuwi-dev-migrate-eslint10": "./scripts/pezkuwi-dev-migrate-eslint10.mjs",
31
32
  "pezkuwi-dev-run-lint": "./scripts/pezkuwi-dev-run-lint.mjs",
32
33
  "pezkuwi-dev-run-node-ts": "./scripts/pezkuwi-dev-run-node-ts.mjs",
33
34
  "pezkuwi-dev-run-test": "./scripts/pezkuwi-dev-run-test.mjs",
@@ -241,6 +242,8 @@
241
242
  "./scripts/pezkuwi-dev-copy-to": "./scripts/pezkuwi-dev-copy-to.mjs",
242
243
  "./scripts/pezkuwi-dev-deno-map.mjs": "./scripts/pezkuwi-dev-deno-map.mjs",
243
244
  "./scripts/pezkuwi-dev-deno-map": "./scripts/pezkuwi-dev-deno-map.mjs",
245
+ "./scripts/pezkuwi-dev-migrate-eslint10.mjs": "./scripts/pezkuwi-dev-migrate-eslint10.mjs",
246
+ "./scripts/pezkuwi-dev-migrate-eslint10": "./scripts/pezkuwi-dev-migrate-eslint10.mjs",
244
247
  "./scripts/pezkuwi-dev-run-lint.mjs": "./scripts/pezkuwi-dev-run-lint.mjs",
245
248
  "./scripts/pezkuwi-dev-run-lint": "./scripts/pezkuwi-dev-run-lint.mjs",
246
249
  "./scripts/pezkuwi-dev-run-node-ts.mjs": "./scripts/pezkuwi-dev-run-node-ts.mjs",
@@ -285,8 +288,8 @@
285
288
  "dependencies": {
286
289
  "@eslint/compat": "^2.1.1",
287
290
  "@eslint/js": "^10.0.1",
288
- "@pezkuwi/dev-test": "^0.86.0",
289
- "@pezkuwi/dev-ts": "^0.86.0",
291
+ "@pezkuwi/dev-test": "^0.86.2",
292
+ "@pezkuwi/dev-ts": "^0.86.2",
290
293
  "@rollup/plugin-alias": "^5.1.1",
291
294
  "@rollup/plugin-commonjs": "^29.0.3",
292
295
  "@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.0' };
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.2' };
@@ -19,7 +19,7 @@ const [e, i] = fs
19
19
 
20
20
  if (!fs.existsSync('mod.ts')) {
21
21
  fs.writeFileSync('mod.ts', `// Copyright 2017-${new Date().getFullYear()} @pezkuwi/dev authors & contributors\n// SPDX-License-Identifier: Apache-2.0\n\n// auto-generated via pezkuwi-dev-deno-map, do not edit\n\n// This is a Deno file, so we can allow .ts imports
22
- /* eslint-disable import/extensions */\n\n${e.join('\n')}\n`);
22
+ /* eslint-disable import-x/extensions */\n\n${e.join('\n')}\n`);
23
23
  }
24
24
 
25
25
  if (fs.existsSync('import_map.in.json')) {
@@ -0,0 +1,176 @@
1
+ #!/usr/bin/env node
2
+ // Copyright 2017-2026 @pezkuwi/dev authors & contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+
5
+ // Renames rules in eslint-disable / eslint-enable comments for the 0.86
6
+ // toolchain (eslint 10, typescript-eslint 8, @stylistic, import-x).
7
+ //
8
+ // A disable comment that names a rule which no longer exists under that name
9
+ // disables nothing: eslint reports it as unused and `--fix` deletes it, after
10
+ // which the rule it was meant to silence applies. Run this before the first
11
+ // lint on 0.86, in the repository root:
12
+ //
13
+ // pezkuwi-dev-migrate-eslint10 # rewrite tracked files
14
+ // pezkuwi-dev-migrate-eslint10 --check # report, change nothing (exit 1 if anything would change)
15
+ //
16
+ // It also rewrites such comments inside string literals, which is how code
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.
20
+
21
+ import stylisticPlugin from '@stylistic/eslint-plugin';
22
+ import { builtinRules } from 'eslint/use-at-your-own-risk';
23
+ import importPlugin from 'eslint-plugin-import-x';
24
+ import { execFileSync } from 'node:child_process';
25
+ import fs from 'node:fs';
26
+
27
+ const STYLISTIC = new Set(Object.keys(stylisticPlugin.rules));
28
+ const IMPORT_X = new Set(Object.keys(importPlugin.rules));
29
+
30
+ /** @type {Map<string, string[]>} */
31
+ const RENAME = new Map();
32
+
33
+ // Core rules eslint 10 deprecated, with the successor it names itself. The
34
+ // rule metadata (meta.deprecated.replacedBy) is only exposed here, so this
35
+ // reads it rather than keeping a hand-written copy that could drift.
36
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
37
+ for (const [name, rule] of builtinRules) {
38
+ const replacedBy = rule.meta?.deprecated && typeof rule.meta.deprecated === 'object'
39
+ ? rule.meta.deprecated.replacedBy
40
+ : undefined;
41
+
42
+ if (replacedBy?.length === 1) {
43
+ const [{ plugin, rule: next }] = replacedBy;
44
+
45
+ if (next?.name) {
46
+ RENAME.set(name, [plugin?.name === '@stylistic/eslint-plugin' ? `@stylistic/${next.name}` : next.name]);
47
+ }
48
+ }
49
+ }
50
+
51
+ // typescript-eslint 8 removed its formatting rules; they live in @stylistic.
52
+ for (const name of ['block-spacing', 'brace-style', 'comma-dangle', 'comma-spacing', 'func-call-spacing', 'indent', 'key-spacing', 'keyword-spacing', 'lines-around-comment', 'lines-between-class-members', 'member-delimiter-style', 'no-extra-parens', 'no-extra-semi', 'object-curly-spacing', 'padding-line-between-statements', 'quotes', 'semi', 'space-before-blocks', 'space-before-function-paren', 'space-infix-ops', 'type-annotation-spacing']) {
53
+ const next = name === 'func-call-spacing' ? 'function-call-spacing' : name;
54
+
55
+ if (STYLISTIC.has(next)) {
56
+ RENAME.set(`@typescript-eslint/${name}`, [`@stylistic/${next}`]);
57
+ }
58
+ }
59
+
60
+ // Other typescript-eslint 8 removals and renames.
61
+ RENAME.set('@typescript-eslint/ban-types', ['@typescript-eslint/no-empty-object-type', '@typescript-eslint/no-unsafe-function-type', '@typescript-eslint/no-wrapper-object-types']);
62
+ RENAME.set('@typescript-eslint/no-empty-interface', ['@typescript-eslint/no-empty-object-type']);
63
+ RENAME.set('@typescript-eslint/no-loss-of-precision', ['no-loss-of-precision']);
64
+ RENAME.set('@typescript-eslint/no-throw-literal', ['@typescript-eslint/only-throw-error']);
65
+ RENAME.set('@typescript-eslint/no-var-requires', ['@typescript-eslint/no-require-imports']);
66
+ RENAME.set('deprecation/deprecation', ['@typescript-eslint/no-deprecated']);
67
+
68
+ // The react formatting rules config/eslint.rules.js (overrideJsx) now takes
69
+ // from @stylistic; keep this list in step with it. (The config is not
70
+ // imported here: loading it reads the repository's tsconfig.base.json.)
71
+ for (const name of ['jsx-closing-bracket-location', 'jsx-first-prop-new-line', 'jsx-max-props-per-line', 'jsx-newline', 'jsx-props-no-multi-spaces', 'jsx-sort-props', 'jsx-tag-spacing']) {
72
+ if (STYLISTIC.has(name)) {
73
+ RENAME.set(`react/${name}`, [`@stylistic/${name}`]);
74
+ }
75
+ }
76
+
77
+ /**
78
+ * @param {string} name
79
+ * @returns {string[]}
80
+ */
81
+ function rename (name) {
82
+ if (RENAME.has(name)) {
83
+ return /** @type {string[]} */ (RENAME.get(name));
84
+ } else if (name.startsWith('import/') && IMPORT_X.has(name.slice(7))) {
85
+ return [`import-x/${name.slice(7)}`];
86
+ }
87
+
88
+ return [name];
89
+ }
90
+
91
+ // eslint-disable, eslint-disable-line, eslint-disable-next-line, eslint-enable
92
+ // followed by a rule list, optionally ending in `-- description`.
93
+ const DIRECTIVE = /(eslint-(?:disable(?:-next-line|-line)?|enable))([ \t]+)([^\n*'"`]*?)([ \t]*(?:--[^\n*]*)?)(?=\*\/|\n|$|['"`])/g;
94
+
95
+ const files = execFileSync('git', ['ls-files', '-z', '--', '*.ts', '*.tsx', '*.js', '*.jsx', '*.mjs', '*.cjs', '*.cts', '*.mts'], { encoding: 'utf-8' })
96
+ .split('\0')
97
+ .filter((f) => f && !/(^|\/)(node_modules|build|build-[^/]+)\//.test(f));
98
+ const check = process.argv.includes('--check');
99
+ let changedFiles = 0;
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
+ }
133
+
134
+ for (const file of files) {
135
+ const src = fs.readFileSync(file, 'utf-8');
136
+ const out = src.replace(DIRECTIVE, (/** @type {string} */ all, /** @type {string} */ kind, /** @type {string} */ gap, /** @type {string} */ list, /** @type {string} */ tail) => {
137
+ if (!list.trim()) {
138
+ return all;
139
+ }
140
+
141
+ const names = list.split(',').map((n) => n.trim()).filter(Boolean);
142
+ const next = [...new Set(names.flatMap(rename))];
143
+
144
+ if (next.join(',') === names.join(',')) {
145
+ return all;
146
+ }
147
+
148
+ changedComments++;
149
+
150
+ return `${kind}${gap}${next.join(', ')}${tail}`;
151
+ });
152
+
153
+ const outKeys = CONFIG_FILE.test(file)
154
+ ? renameConfigKeys(file, out)
155
+ : out;
156
+
157
+ if (outKeys !== src) {
158
+ changedFiles++;
159
+
160
+ if (check) {
161
+ console.log(`would change: ${file}`);
162
+ } else {
163
+ fs.writeFileSync(file, outKeys);
164
+ }
165
+ }
166
+ }
167
+
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)`);
173
+
174
+ if ((check && changedFiles) || manual.length) {
175
+ process.exit(1);
176
+ }