miniread 1.77.0 → 1.79.0

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.
@@ -13,7 +13,7 @@
13
13
  * - Stable names (`$timeoutId`): Readable AND deterministic across versions
14
14
  * - Readable names (`timeoutId`): Semantic but order-dependent
15
15
  */
16
- import type { Scope } from "@babel/traverse";
16
+ import type { Binding, Scope } from "@babel/traverse";
17
17
  /**
18
18
  * Returns true if the name has been stable-renamed (starts with $).
19
19
  * Transforms should skip variables with this prefix.
@@ -25,6 +25,11 @@ export declare const isStableRenamed: (name: string) => boolean;
25
25
  * stabilized by one of the hash-based stabilization transforms.
26
26
  */
27
27
  export declare const isHashBasedStableName: (name: string) => boolean;
28
+ /**
29
+ * Returns true only when the exact stable name slot (`$${baseName}`) is
30
+ * available for this binding in the provided scope.
31
+ */
32
+ export declare const canUseExactStableName: (scope: Scope, binding: Binding | undefined, currentName: string, baseName: string) => boolean;
28
33
  /**
29
34
  * Entry for a planned rename operation.
30
35
  */
@@ -29,6 +29,23 @@ export const isStableRenamed = (name) => {
29
29
  * stabilized by one of the hash-based stabilization transforms.
30
30
  */
31
31
  export const isHashBasedStableName = (name) => name.startsWith("$h_") || name.startsWith("$f_") || name.startsWith("$v_");
32
+ /**
33
+ * Returns true only when the exact stable name slot (`$${baseName}`) is
34
+ * available for this binding in the provided scope.
35
+ */
36
+ export const canUseExactStableName = (scope, binding, currentName, baseName) => {
37
+ const candidateStable = makeStableName(baseName);
38
+ const programGlobals = getProgramValueGlobals(scope);
39
+ const stableTaken = candidateStable === currentName
40
+ ? false
41
+ : scope.hasBinding(candidateStable) ||
42
+ programGlobals.has(candidateStable);
43
+ if (stableTaken)
44
+ return false;
45
+ if (binding && hasShadowingRisk(binding, scope, candidateStable))
46
+ return false;
47
+ return true;
48
+ };
32
49
  /**
33
50
  * Creates a stable name by adding the $ prefix.
34
51
  * Internal helper - prefer using RenameGroup which handles stability logic automatically.
@@ -168,10 +168,19 @@ const manifestData = {
168
168
  recommended: true,
169
169
  evaluations: { "claude-code-2.1.10:claude-code-2.1.11": { "diffSizePercent": 100, "evaluatedAt": "2026-02-04T12:54:37.434Z", "changedLines": 14, "durationSeconds": 231.553556391, "stableNames": 1358 } },
170
170
  },
171
+ "rename-indexeddb-request-variables": {
172
+ recommended: true,
173
+ evaluations: { "claude-code-2.1.10:claude-code-2.1.11": { "diffSizePercent": 100, "evaluatedAt": "2026-02-06T14:48:25.555Z", "changedLines": 30, "durationSeconds": 226.960178979, "stableNames": 1358 } },
174
+ },
171
175
  "rename-interval-ids": {
172
176
  recommended: true,
173
177
  evaluations: { "claude-code-2.1.10:claude-code-2.1.11": { "diffSizePercent": 100, "evaluatedAt": "2026-02-01T09:30:55.276Z", "changedLines": 58, "durationSeconds": 201.398360841, "stableNames": 1358 } },
174
178
  },
179
+ "rename-invalid-parameter-arguments": {
180
+ recommended: true,
181
+ notes: "Added to recommended for readability of invalidParameterError call sites.",
182
+ evaluations: { "claude-code-2.1.10:claude-code-2.1.11": { "diffSizePercent": 99.99811516350957, "evaluatedAt": "2026-02-06T12:52:02.935Z", "changedLines": 452, "durationSeconds": 211.048545671, "stableNames": 1381 } },
183
+ },
175
184
  "rename-loop-index-variables": {
176
185
  recommended: false,
177
186
  notes: "Superseded by rename-loop-index-variables-v3.",
@@ -455,12 +464,14 @@ export const recommendedTransformIds = [
455
464
  "rename-fs-sync-variables",
456
465
  "rename-http-method-parameters",
457
466
  "rename-interval-ids",
467
+ "rename-indexeddb-request-variables",
458
468
  "rename-loop-index-variables-v3",
459
469
  "rename-loop-length-variables",
460
470
  "rename-document-fragment-variables",
461
471
  "rename-object-keys-variables",
462
472
  "rename-object-keys-iterator-variables",
463
473
  "rename-parameters-to-match-properties-v2",
474
+ "rename-invalid-parameter-arguments",
464
475
  "rename-promise-executor-parameters-v2",
465
476
  "rename-range-parameters",
466
477
  "rename-read-file-lines",
@@ -34,7 +34,9 @@ import { renameFileReaderVariablesTransform } from "../rename-file-reader-variab
34
34
  import { renameFsSyncVariablesTransform } from "../rename-fs-sync-variables/rename-fs-sync-variables-transform.js";
35
35
  import { renameHttpMethodParametersTransform } from "../rename-http-method-parameters/rename-http-method-parameters-transform.js";
36
36
  import { renameHttpServerParametersTransform } from "../rename-http-server-parameters/rename-http-server-parameters-transform.js";
37
+ import { renameIndexeddbRequestVariablesTransform } from "../rename-indexeddb-request-variables/rename-indexeddb-request-variables-transform.js";
37
38
  import { renameIntervalIdsTransform } from "../rename-interval-ids/rename-interval-ids-transform.js";
39
+ import { renameInvalidParameterArgumentsTransform } from "../rename-invalid-parameter-arguments/rename-invalid-parameter-arguments-transform.js";
38
40
  import { renameLoopIndexVariablesTransform } from "../rename-loop-index-variables/rename-loop-index-variables-transform.js";
39
41
  import { renameLoopIndexVariablesV2Transform } from "../rename-loop-index-variables-v2/rename-loop-index-variables-v2-transform.js";
40
42
  import { renameLoopIndexVariablesV3Transform } from "../rename-loop-index-variables-v3/rename-loop-index-variables-v3-transform.js";
@@ -117,7 +119,9 @@ export const transformRegistry = {
117
119
  [renameFsSyncVariablesTransform.id]: renameFsSyncVariablesTransform,
118
120
  [renameHttpMethodParametersTransform.id]: renameHttpMethodParametersTransform,
119
121
  [renameHttpServerParametersTransform.id]: renameHttpServerParametersTransform,
122
+ [renameIndexeddbRequestVariablesTransform.id]: renameIndexeddbRequestVariablesTransform,
120
123
  [renameIntervalIdsTransform.id]: renameIntervalIdsTransform,
124
+ [renameInvalidParameterArgumentsTransform.id]: renameInvalidParameterArgumentsTransform,
121
125
  [renameLoopIndexVariablesTransform.id]: renameLoopIndexVariablesTransform,
122
126
  [renameLoopIndexVariablesV2Transform.id]: renameLoopIndexVariablesV2Transform,
123
127
  [renameLoopIndexVariablesV3Transform.id]: renameLoopIndexVariablesV3Transform,
@@ -0,0 +1,2 @@
1
+ import type { Binding } from "@babel/traverse";
2
+ export declare const getBindingStableStart: (binding: Binding) => number;
@@ -0,0 +1,11 @@
1
+ const BINDING_INDEX_SCALE = 1_000_000;
2
+ export const getBindingStableStart = (binding) => {
3
+ const start = binding.identifier.start;
4
+ if (typeof start === "number")
5
+ return start;
6
+ const location = binding.identifier.loc;
7
+ if (location) {
8
+ return location.start.line * BINDING_INDEX_SCALE + location.start.column;
9
+ }
10
+ return Number.MAX_SAFE_INTEGER;
11
+ };
@@ -4,4 +4,4 @@
4
4
  * This lets us tune transform interactions intentionally instead of relying on
5
5
  * alphabetical ID sorting.
6
6
  */
7
- export declare const recommendedTransformOrder: readonly ["stabilize-top-level-bindings", "stabilize-nested-bindings", "stabilize-deferred-top-level-bindings", "stabilize-deferred-stable-rhs", "expand-boolean-literals", "expand-sequence-expressions-v5", "expand-special-number-literals", "expand-typeof-undefined-comparisons", "expand-undefined-literals", "remove-redundant-else", "rename-arguments-length-flags", "rename-asap-wrappers", "rename-awaiter-parameters", "rename-awaiter-helper-functions", "rename-buffer-variables", "rename-to-buffer-results", "rename-catch-parameters", "rename-promise-catch-parameters", "rename-char-code-at", "rename-charcode-variables-v2", "rename-client-aliases", "rename-comparison-flags", "rename-date-now-start-times", "rename-default-options-parameters-v2", "rename-deferred-resolve-parameters", "rename-destructured-aliases", "rename-rest-parameters", "rename-execfile-arguments", "rename-file-reader-variables", "rename-error-first-callback-parameters", "rename-error-first-callback-parameters-v2", "rename-error-variables", "rename-event-parameters", "rename-http-server-parameters", "rename-fs-sync-variables", "rename-http-method-parameters", "rename-interval-ids", "rename-loop-index-variables-v3", "rename-loop-length-variables", "rename-document-fragment-variables", "rename-object-keys-variables", "rename-object-keys-iterator-variables", "rename-parameters-to-match-properties-v2", "rename-promise-executor-parameters-v2", "rename-range-parameters", "rename-read-file-lines", "rename-regex-builders", "rename-regex-source-parameters", "rename-search-parameters-variables", "rename-file-extension-variables", "rename-string-split-variables", "rename-this-aliases", "rename-timeout-promises", "rename-timeout-ids", "rename-typeof-variables", "rename-typescript-helper-aliases", "rename-uint8array-concat-variables", "rename-url-parameters", "rename-url-variables", "rename-use-reference-guards-v2", "rename-use-reference-sets", "rename-worker-handles", "rename-zod-check-parameters", "simplify-boolean-negations", "simplify-string-trim", "split-variable-declarations", "use-optional-chaining", "use-object-property-shorthand", "use-object-shorthand", "replace-dynamic-require-eval"];
7
+ export declare const recommendedTransformOrder: readonly ["stabilize-top-level-bindings", "stabilize-nested-bindings", "stabilize-deferred-top-level-bindings", "stabilize-deferred-stable-rhs", "expand-boolean-literals", "expand-sequence-expressions-v5", "expand-special-number-literals", "expand-typeof-undefined-comparisons", "expand-undefined-literals", "remove-redundant-else", "rename-arguments-length-flags", "rename-asap-wrappers", "rename-awaiter-parameters", "rename-awaiter-helper-functions", "rename-buffer-variables", "rename-to-buffer-results", "rename-catch-parameters", "rename-promise-catch-parameters", "rename-char-code-at", "rename-charcode-variables-v2", "rename-client-aliases", "rename-comparison-flags", "rename-date-now-start-times", "rename-default-options-parameters-v2", "rename-deferred-resolve-parameters", "rename-destructured-aliases", "rename-rest-parameters", "rename-execfile-arguments", "rename-file-reader-variables", "rename-error-first-callback-parameters", "rename-error-first-callback-parameters-v2", "rename-error-variables", "rename-event-parameters", "rename-http-server-parameters", "rename-fs-sync-variables", "rename-http-method-parameters", "rename-interval-ids", "rename-indexeddb-request-variables", "rename-loop-index-variables-v3", "rename-loop-length-variables", "rename-document-fragment-variables", "rename-object-keys-variables", "rename-object-keys-iterator-variables", "rename-parameters-to-match-properties-v2", "rename-invalid-parameter-arguments", "rename-promise-executor-parameters-v2", "rename-range-parameters", "rename-read-file-lines", "rename-regex-builders", "rename-regex-source-parameters", "rename-search-parameters-variables", "rename-file-extension-variables", "rename-string-split-variables", "rename-this-aliases", "rename-timeout-promises", "rename-timeout-ids", "rename-typeof-variables", "rename-typescript-helper-aliases", "rename-uint8array-concat-variables", "rename-url-parameters", "rename-url-variables", "rename-use-reference-guards-v2", "rename-use-reference-sets", "rename-worker-handles", "rename-zod-check-parameters", "simplify-boolean-negations", "simplify-string-trim", "split-variable-declarations", "use-optional-chaining", "use-object-property-shorthand", "use-object-shorthand", "replace-dynamic-require-eval"];
@@ -54,12 +54,14 @@ export const recommendedTransformOrder = [
54
54
  "rename-fs-sync-variables",
55
55
  "rename-http-method-parameters",
56
56
  "rename-interval-ids",
57
+ "rename-indexeddb-request-variables",
57
58
  "rename-loop-index-variables-v3",
58
59
  "rename-loop-length-variables",
59
60
  "rename-document-fragment-variables",
60
61
  "rename-object-keys-variables",
61
62
  "rename-object-keys-iterator-variables",
62
63
  "rename-parameters-to-match-properties-v2",
64
+ "rename-invalid-parameter-arguments",
63
65
  "rename-promise-executor-parameters-v2",
64
66
  "rename-range-parameters",
65
67
  "rename-read-file-lines",
@@ -2,6 +2,7 @@ import { createRequire } from "node:module";
2
2
  import { collectExportedNames } from "../../core/collect-exported-names.js";
3
3
  import { isStableRenamed, RenameGroup } from "../../core/stable-naming.js";
4
4
  import { getFilesToProcess, } from "../../core/types.js";
5
+ import { getBindingStableStart } from "../get-binding-stable-start.js";
5
6
  import { hasDynamicNameLookup } from "../has-dynamic-name-lookup.js";
6
7
  import { isNodeFileSystemNamespaceBinding } from "../is-node-file-system-identifier.js";
7
8
  const require = createRequire(import.meta.url);
@@ -56,15 +57,6 @@ const shouldRename = (identifier) => {
56
57
  return false;
57
58
  return true;
58
59
  };
59
- const getBindingStableStart = (binding) => {
60
- const start = binding.identifier.start;
61
- if (typeof start === "number")
62
- return start;
63
- const loc = binding.identifier.loc;
64
- if (loc)
65
- return loc.start.line * 1_000_000 + loc.start.column;
66
- return Number.MAX_SAFE_INTEGER;
67
- };
68
60
  export const renameFsSyncVariablesTransform = {
69
61
  id: "rename-fs-sync-variables",
70
62
  description: "Renames Node fs bindings used with 2+ distinct fs.*Sync methods to stable fs-based names",
@@ -0,0 +1,10 @@
1
+ import type { Binding } from "@babel/traverse";
2
+ import type { CallExpression, OptionalCallExpression } from "@babel/types";
3
+ type RequestMethodName = "open" | "deleteDatabase";
4
+ type RequestUsage = {
5
+ properties: Set<string>;
6
+ };
7
+ export declare const getIndexedDatabaseRequestInitMethod: (init: CallExpression | OptionalCallExpression) => RequestMethodName | undefined;
8
+ export declare const getIndexedDBRequestUsage: (binding: Binding) => RequestUsage | undefined;
9
+ export declare const hasOpenRequestSpecificSignals: (properties: Set<string>) => boolean;
10
+ export {};
@@ -0,0 +1,86 @@
1
+ const REQUEST_MEMBER_PROPERTIES = new Set([
2
+ "onerror",
3
+ "onsuccess",
4
+ "onblocked",
5
+ "onupgradeneeded",
6
+ "result",
7
+ "error",
8
+ "transaction",
9
+ ]);
10
+ const OPEN_ONLY_SPECIFIC_PROPERTIES = new Set([
11
+ "onblocked",
12
+ "onupgradeneeded",
13
+ "transaction",
14
+ ]);
15
+ const REQUEST_EVENT_HANDLER_PROPERTIES = new Set([
16
+ "onsuccess",
17
+ "onerror",
18
+ "onblocked",
19
+ "onupgradeneeded",
20
+ ]);
21
+ const REQUEST_VALUE_PROPERTIES = new Set(["result", "error"]);
22
+ const getMemberPropertyName = (member) => {
23
+ if (member.computed) {
24
+ if (member.property.type !== "StringLiteral")
25
+ return;
26
+ return member.property.value;
27
+ }
28
+ if (member.property.type !== "Identifier")
29
+ return;
30
+ return member.property.name;
31
+ };
32
+ export const getIndexedDatabaseRequestInitMethod = (init) => {
33
+ const callee = init.callee;
34
+ if (callee.type !== "MemberExpression" &&
35
+ callee.type !== "OptionalMemberExpression") {
36
+ return undefined;
37
+ }
38
+ const propertyName = getMemberPropertyName(callee);
39
+ if (!propertyName)
40
+ return undefined;
41
+ if (propertyName === "open")
42
+ return "open";
43
+ // `deleteDatabase` is distinctive enough that we intentionally avoid
44
+ // receiver-origin checks to preserve support for aliased IDB factories.
45
+ if (propertyName === "deleteDatabase")
46
+ return "deleteDatabase";
47
+ return undefined;
48
+ };
49
+ export const getIndexedDBRequestUsage = (binding) => {
50
+ const properties = new Set();
51
+ for (const referencePath of binding.referencePaths) {
52
+ // Be conservative: if any reference is not a direct request member access,
53
+ // skip renaming to avoid mislabeling generic `.open()` call results.
54
+ if (!referencePath.isIdentifier())
55
+ return;
56
+ const parentPath = referencePath.parentPath;
57
+ if (!parentPath.isMemberExpression() &&
58
+ !parentPath.isOptionalMemberExpression()) {
59
+ return;
60
+ }
61
+ const memberExpression = parentPath.node;
62
+ if (memberExpression.object !== referencePath.node)
63
+ return;
64
+ const propertyName = getMemberPropertyName(memberExpression);
65
+ if (!propertyName)
66
+ return;
67
+ if (!REQUEST_MEMBER_PROPERTIES.has(propertyName))
68
+ return;
69
+ properties.add(propertyName);
70
+ }
71
+ return { properties };
72
+ };
73
+ const hasAnyProperty = (properties, allowedProperties) => {
74
+ for (const property of properties) {
75
+ if (allowedProperties.has(property))
76
+ return true;
77
+ }
78
+ return false;
79
+ };
80
+ export const hasOpenRequestSpecificSignals = (properties) =>
81
+ // `open()` is generic across APIs, so we require either IndexedDB-specific
82
+ // signals (`onblocked`/`onupgradeneeded`/`transaction`) or the paired
83
+ // request pattern (event callback + `result`/`error`) used by IDB requests.
84
+ hasAnyProperty(properties, OPEN_ONLY_SPECIFIC_PROPERTIES) ||
85
+ (hasAnyProperty(properties, REQUEST_EVENT_HANDLER_PROPERTIES) &&
86
+ hasAnyProperty(properties, REQUEST_VALUE_PROPERTIES));
@@ -0,0 +1,12 @@
1
+ {
2
+ "recommended": true,
3
+ "evaluations": {
4
+ "claude-code-2.1.10:claude-code-2.1.11": {
5
+ "diffSizePercent": 100,
6
+ "evaluatedAt": "2026-02-06T14:48:25.555Z",
7
+ "changedLines": 30,
8
+ "durationSeconds": 226.960178979,
9
+ "stableNames": 1358
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,2 @@
1
+ import { type Transform } from "../../core/types.js";
2
+ export declare const renameIndexeddbRequestVariablesTransform: Transform;
@@ -0,0 +1,100 @@
1
+ import { createRequire } from "node:module";
2
+ import { getIndexedDatabaseRequestInitMethod, getIndexedDBRequestUsage, hasOpenRequestSpecificSignals, } from "./analyze-indexeddb-request-binding.js";
3
+ import { collectExportedNames } from "../../core/collect-exported-names.js";
4
+ import { isStableRenamed, RenameGroup } from "../../core/stable-naming.js";
5
+ import { getFilesToProcess, } from "../../core/types.js";
6
+ import { getBindingStableStart } from "../get-binding-stable-start.js";
7
+ import { hasDynamicNameLookup } from "../has-dynamic-name-lookup.js";
8
+ const require = createRequire(import.meta.url);
9
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
10
+ const traverse = require("@babel/traverse").default;
11
+ const BASE_NAME = "dbRequest";
12
+ const getRequestMethod = (init) => {
13
+ if (init?.type !== "CallExpression" &&
14
+ init?.type !== "OptionalCallExpression") {
15
+ return undefined;
16
+ }
17
+ return getIndexedDatabaseRequestInitMethod(init);
18
+ };
19
+ export const renameIndexeddbRequestVariablesTransform = {
20
+ id: "rename-indexeddb-request-variables",
21
+ description: "Renames IndexedDB open/deleteDatabase request bindings to stable dbRequest names based on request event usage",
22
+ scope: "file",
23
+ parallelizable: true,
24
+ transform(context) {
25
+ let nodesVisited = 0;
26
+ let transformationsApplied = 0;
27
+ for (const fileInfo of getFilesToProcess(context)) {
28
+ if (hasDynamicNameLookup(fileInfo.ast))
29
+ continue;
30
+ const renameCandidatesByScope = new Map();
31
+ const isScript = fileInfo.ast.program.sourceType === "script";
32
+ const exportedNames = collectExportedNames(fileInfo.ast.program);
33
+ traverse(fileInfo.ast, {
34
+ VariableDeclarator(path) {
35
+ nodesVisited++;
36
+ const id = path.node.id;
37
+ if (id.type !== "Identifier")
38
+ return;
39
+ if (isStableRenamed(id.name))
40
+ return;
41
+ if (id.name.toLowerCase().includes("request"))
42
+ return;
43
+ const initMethod = getRequestMethod(path.node.init);
44
+ if (!initMethod)
45
+ return;
46
+ const binding = path.scope.getBinding(id.name);
47
+ if (!binding)
48
+ return;
49
+ if (!binding.constant)
50
+ return;
51
+ if (binding.referencePaths.length === 0)
52
+ return;
53
+ if (isScript && binding.scope.block.type === "Program")
54
+ return;
55
+ if (binding.scope.block.type === "Program" &&
56
+ exportedNames.has(id.name)) {
57
+ return;
58
+ }
59
+ const usage = getIndexedDBRequestUsage(binding);
60
+ if (!usage)
61
+ return;
62
+ if (usage.properties.size < 2)
63
+ return;
64
+ if (initMethod === "open" &&
65
+ !hasOpenRequestSpecificSignals(usage.properties)) {
66
+ return;
67
+ }
68
+ const existing = renameCandidatesByScope.get(binding.scope);
69
+ if (existing) {
70
+ existing.push(binding);
71
+ }
72
+ else {
73
+ renameCandidatesByScope.set(binding.scope, [binding]);
74
+ }
75
+ },
76
+ });
77
+ for (const [scope, bindings] of renameCandidatesByScope) {
78
+ bindings.sort((a, b) => {
79
+ const aStart = getBindingStableStart(a);
80
+ const bStart = getBindingStableStart(b);
81
+ if (aStart !== bStart)
82
+ return aStart - bStart;
83
+ return a.identifier.name.localeCompare(b.identifier.name);
84
+ });
85
+ for (const binding of bindings) {
86
+ // Apply per binding to force stable `$dbRequest` slots (`$dbRequest`,
87
+ // `$dbRequest2`, ...) even when multiple request bindings share scope.
88
+ const group = new RenameGroup();
89
+ group.add({
90
+ scope,
91
+ currentName: binding.identifier.name,
92
+ baseName: BASE_NAME,
93
+ });
94
+ transformationsApplied += group.apply();
95
+ }
96
+ }
97
+ }
98
+ return Promise.resolve({ nodesVisited, transformationsApplied });
99
+ },
100
+ };
@@ -0,0 +1,13 @@
1
+ {
2
+ "recommended": true,
3
+ "notes": "Added to recommended for readability of invalidParameterError call sites.",
4
+ "evaluations": {
5
+ "claude-code-2.1.10:claude-code-2.1.11": {
6
+ "diffSizePercent": 99.99811516350957,
7
+ "evaluatedAt": "2026-02-06T12:52:02.935Z",
8
+ "changedLines": 452,
9
+ "durationSeconds": 211.048545671,
10
+ "stableNames": 1381
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,2 @@
1
+ import { type Transform } from "../../core/types.js";
2
+ export declare const renameInvalidParameterArgumentsTransform: Transform;
@@ -0,0 +1,142 @@
1
+ import { createRequire } from "node:module";
2
+ import { isIdentifierName, isKeyword, isStrictBindReservedWord, } from "@babel/helper-validator-identifier";
3
+ import { RenameGroup, canUseExactStableName, isStableRenamed, } from "../../core/stable-naming.js";
4
+ import { getFilesToProcess, } from "../../core/types.js";
5
+ const require = createRequire(import.meta.url);
6
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
7
+ const traverse = require("@babel/traverse").default;
8
+ const getValidBaseName = (value) => {
9
+ const trimmed = value.trim();
10
+ if (trimmed.length === 0)
11
+ return undefined;
12
+ const normalized = trimmed.replace(/^\$+/u, "");
13
+ if (normalized.length === 0)
14
+ return undefined;
15
+ if (!isIdentifierName(normalized))
16
+ return undefined;
17
+ if (normalized.startsWith("h_"))
18
+ return undefined;
19
+ if (normalized.startsWith("f_"))
20
+ return undefined;
21
+ if (normalized.startsWith("v_"))
22
+ return undefined;
23
+ // Keep module-mode strictness to avoid introducing bindings that become
24
+ // invalid when sourceType resolves to module in unambiguous parsing.
25
+ if (isKeyword(normalized) || isStrictBindReservedWord(normalized, true)) {
26
+ return undefined;
27
+ }
28
+ return normalized;
29
+ };
30
+ const isInvalidParameterErrorCallee = (callee) => {
31
+ if (callee.type === "Identifier") {
32
+ return callee.name === "invalidParameterError";
33
+ }
34
+ if (callee.type !== "MemberExpression")
35
+ return false;
36
+ if (callee.object.type !== "Identifier")
37
+ return false;
38
+ if (callee.object.name !== "errors")
39
+ return false;
40
+ if (callee.computed)
41
+ return false;
42
+ if (callee.property.type !== "Identifier")
43
+ return false;
44
+ return callee.property.name === "invalidParameterError";
45
+ };
46
+ const getInvalidParameterRename = (path) => {
47
+ if (!isInvalidParameterErrorCallee(path.node.callee))
48
+ return undefined;
49
+ if (path.node.arguments.length !== 3)
50
+ return undefined;
51
+ const [nameArgument, expectedTypeArgument, valueArgument] = path.node.arguments;
52
+ if (nameArgument?.type !== "StringLiteral")
53
+ return undefined;
54
+ // Keep this intentionally strict: we only rename for the canonical
55
+ // invalidParameterError("name", "expected", actual) signature.
56
+ if (expectedTypeArgument?.type !== "StringLiteral")
57
+ return undefined;
58
+ if (valueArgument?.type !== "Identifier")
59
+ return undefined;
60
+ const baseName = getValidBaseName(nameArgument.value);
61
+ if (!baseName)
62
+ return undefined;
63
+ const binding = path.scope.getBinding(valueArgument.name);
64
+ if (!binding)
65
+ return undefined;
66
+ if (binding.kind !== "param")
67
+ return undefined;
68
+ if (isStableRenamed(binding.identifier.name))
69
+ return undefined;
70
+ // Preserve already-semantic parameter names instead of forcing `$name`.
71
+ if (binding.identifier.name === baseName)
72
+ return undefined;
73
+ return {
74
+ baseName,
75
+ binding,
76
+ scope: binding.scope,
77
+ };
78
+ };
79
+ export const renameInvalidParameterArgumentsTransform = {
80
+ id: "rename-invalid-parameter-arguments",
81
+ description: 'Renames minified parameters passed to invalidParameterError("name", ...) to matching names, preferring stable $name when unambiguous and available.',
82
+ scope: "file",
83
+ parallelizable: true,
84
+ transform(context) {
85
+ let nodesVisited = 0;
86
+ let transformationsApplied = 0;
87
+ for (const fileInfo of getFilesToProcess(context)) {
88
+ const group = new RenameGroup();
89
+ const candidateByBinding = new Map();
90
+ const conflictedBindings = new Set();
91
+ traverse(fileInfo.ast, {
92
+ CallExpression(path) {
93
+ nodesVisited++;
94
+ const candidate = getInvalidParameterRename(path);
95
+ if (!candidate)
96
+ return;
97
+ if (conflictedBindings.has(candidate.binding))
98
+ return;
99
+ const existing = candidateByBinding.get(candidate.binding);
100
+ if (!existing) {
101
+ candidateByBinding.set(candidate.binding, candidate);
102
+ return;
103
+ }
104
+ if (existing.baseName === candidate.baseName)
105
+ return;
106
+ candidateByBinding.delete(candidate.binding);
107
+ conflictedBindings.add(candidate.binding);
108
+ },
109
+ });
110
+ const baseNameCountsByScope = new Map();
111
+ for (const candidate of candidateByBinding.values()) {
112
+ let countByBaseName = baseNameCountsByScope.get(candidate.scope);
113
+ if (!countByBaseName) {
114
+ countByBaseName = new Map();
115
+ baseNameCountsByScope.set(candidate.scope, countByBaseName);
116
+ }
117
+ countByBaseName.set(candidate.baseName, (countByBaseName.get(candidate.baseName) ?? 0) + 1);
118
+ }
119
+ for (const candidate of candidateByBinding.values()) {
120
+ const countByBaseName = baseNameCountsByScope.get(candidate.scope);
121
+ if (!countByBaseName)
122
+ continue;
123
+ const baseNameCount = countByBaseName.get(candidate.baseName);
124
+ if (!baseNameCount || baseNameCount > 1)
125
+ continue;
126
+ if (!canUseExactStableName(candidate.scope, candidate.binding, candidate.binding.identifier.name, candidate.baseName)) {
127
+ continue;
128
+ }
129
+ group.add({
130
+ scope: candidate.scope,
131
+ currentName: candidate.binding.identifier.name,
132
+ baseName: candidate.baseName,
133
+ });
134
+ }
135
+ transformationsApplied += group.apply();
136
+ }
137
+ return Promise.resolve({
138
+ nodesVisited,
139
+ transformationsApplied,
140
+ });
141
+ },
142
+ };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "miniread",
3
3
  "author": "Łukasz Jerciński",
4
4
  "license": "MIT",
5
- "version": "1.77.0",
5
+ "version": "1.79.0",
6
6
  "description": "Transform minified JavaScript/TypeScript into a more readable form using deterministic AST-based transforms.",
7
7
  "repository": {
8
8
  "type": "git",