miniread 1.10.0 → 1.11.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.
@@ -0,0 +1,7 @@
1
+ type CreateOutputSlugOptions = {
2
+ transforms: string[];
3
+ recommendedTransforms: readonly string[];
4
+ allTransformIds: readonly string[];
5
+ };
6
+ export declare const createOutputSlug: (options: CreateOutputSlugOptions) => string;
7
+ export {};
@@ -0,0 +1,38 @@
1
+ import crypto from "node:crypto";
2
+ import { sanitizeFileComponent } from "./sanitize.js";
3
+ const isSameOrderedList = (a, b) => {
4
+ if (a.length !== b.length)
5
+ return false;
6
+ for (const [index, value] of a.entries()) {
7
+ const other = b[index];
8
+ if (other === undefined)
9
+ return false;
10
+ if (value !== other)
11
+ return false;
12
+ }
13
+ return true;
14
+ };
15
+ const createRawTransformSlug = (options) => {
16
+ const { transforms, recommendedTransforms, allTransformIds } = options;
17
+ if (transforms.length === 0)
18
+ return "none";
19
+ if (isSameOrderedList(transforms, recommendedTransforms))
20
+ return "recommended";
21
+ if (isSameOrderedList(transforms, allTransformIds))
22
+ return "all";
23
+ return transforms.join("-");
24
+ };
25
+ export const createOutputSlug = (options) => {
26
+ const sanitized = sanitizeFileComponent(createRawTransformSlug(options));
27
+ const maxLength = 120;
28
+ if (sanitized.length <= maxLength)
29
+ return sanitized;
30
+ const hash = crypto
31
+ .createHash("sha256")
32
+ .update(sanitized)
33
+ .digest("hex")
34
+ .slice(0, 10);
35
+ const prefixLength = maxLength - hash.length - 1;
36
+ const prefix = sanitized.slice(0, Math.max(0, prefixLength));
37
+ return `${prefix}-${hash}`;
38
+ };
@@ -5,7 +5,6 @@ export type DiffStats = {
5
5
  removedLines: number;
6
6
  changedHunks: number;
7
7
  };
8
- export declare const createTransformSlug: (transforms: string[]) => string;
9
8
  type ComputeDirectoryDiffOptions = {
10
9
  diffPath: string;
11
10
  directoryA: string;
@@ -4,9 +4,6 @@ import fs from "node:fs";
4
4
  import * as fsPromises from "node:fs/promises";
5
5
  import path from "node:path";
6
6
  import readline from "node:readline";
7
- export const createTransformSlug = (transforms) => {
8
- return transforms.length > 0 ? transforms.join("-") : "none";
9
- };
10
7
  const isErrnoException = (error) => {
11
8
  return error instanceof Error;
12
9
  };
@@ -1,8 +1,7 @@
1
1
  import path from "node:path";
2
2
  import { transformPresets } from "../../transforms/transform-presets.js";
3
3
  import { allTransformIds } from "../../transforms/transform-registry.js";
4
- import { createTransformSlug } from "./diff-utilities.js";
5
- import { sanitizeFileComponent } from "./sanitize.js";
4
+ import { createOutputSlug } from "./create-output-slug.js";
6
5
  const parseTransformList = (value) => {
7
6
  if (!value || value === "none")
8
7
  return [];
@@ -66,8 +65,16 @@ export const parseEvaluateCliOptions = (options) => {
66
65
  const verbose = rawOptions.verbose ?? false;
67
66
  const overwrite = rawOptions.overwrite ?? false;
68
67
  const formatCode = rawOptions.formatCode;
69
- const baselineSlug = sanitizeFileComponent(createTransformSlug(baselineTransforms));
70
- const testSlug = sanitizeFileComponent(createTransformSlug(testTransforms));
68
+ const baselineSlug = createOutputSlug({
69
+ transforms: baselineTransforms,
70
+ recommendedTransforms: transformPresets.recommended,
71
+ allTransformIds,
72
+ });
73
+ const testSlug = createOutputSlug({
74
+ transforms: testTransforms,
75
+ recommendedTransforms: transformPresets.recommended,
76
+ allTransformIds,
77
+ });
71
78
  const sourcesDirectory = path.resolve(cwd, rawOptions.sources);
72
79
  const evaluationDirectory = path.resolve(cwd, rawOptions.evaluationDir);
73
80
  const manifestPath = path.resolve(cwd, rawOptions.manifestFile);
@@ -0,0 +1,2 @@
1
+ import { type Transform } from "../../core/types.js";
2
+ export declare const renameThisAliasesTransform: Transform;
@@ -0,0 +1,121 @@
1
+ import { createRequire } from "node:module";
2
+ import { isArrayPattern, isAssignmentPattern, isClassDeclaration, isExportNamedDeclaration, isExportSpecifier, isFunctionDeclaration, isIdentifier, isObjectPattern, isObjectProperty, isRestElement, isVariableDeclaration, } from "@babel/types";
3
+ import { isStableRenamed, RenameGroup } 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 BASE_NAME = "thisRef";
9
+ const addBindingNamesFromNode = (node, out) => {
10
+ const babelNode = node;
11
+ if (!babelNode)
12
+ return;
13
+ if (babelNode.type === "VoidPattern")
14
+ return;
15
+ if (isIdentifier(babelNode)) {
16
+ out.add(babelNode.name);
17
+ return;
18
+ }
19
+ if (isObjectPattern(babelNode)) {
20
+ for (const property of babelNode.properties) {
21
+ if (isRestElement(property)) {
22
+ addBindingNamesFromNode(property.argument, out);
23
+ continue;
24
+ }
25
+ if (!isObjectProperty(property))
26
+ continue;
27
+ addBindingNamesFromNode(property.value, out);
28
+ }
29
+ return;
30
+ }
31
+ if (isArrayPattern(babelNode)) {
32
+ for (const element of babelNode.elements) {
33
+ addBindingNamesFromNode(element, out);
34
+ }
35
+ return;
36
+ }
37
+ if (isRestElement(babelNode)) {
38
+ addBindingNamesFromNode(babelNode.argument, out);
39
+ return;
40
+ }
41
+ if (isAssignmentPattern(babelNode)) {
42
+ addBindingNamesFromNode(babelNode.left, out);
43
+ }
44
+ };
45
+ const collectExportedNames = (program) => {
46
+ const exportedNames = new Set();
47
+ for (const statement of program.body) {
48
+ if (!isExportNamedDeclaration(statement))
49
+ continue;
50
+ const declaration = statement.declaration;
51
+ if (declaration) {
52
+ if (isVariableDeclaration(declaration)) {
53
+ for (const declarator of declaration.declarations) {
54
+ addBindingNamesFromNode(declarator.id, exportedNames);
55
+ }
56
+ }
57
+ else if (isFunctionDeclaration(declaration) ||
58
+ isClassDeclaration(declaration)) {
59
+ const id = declaration.id;
60
+ if (!id)
61
+ continue;
62
+ exportedNames.add(id.name);
63
+ }
64
+ }
65
+ for (const specifier of statement.specifiers) {
66
+ if (!isExportSpecifier(specifier))
67
+ continue;
68
+ const local = specifier.local;
69
+ if (!isIdentifier(local))
70
+ continue;
71
+ exportedNames.add(local.name);
72
+ }
73
+ }
74
+ return exportedNames;
75
+ };
76
+ export const renameThisAliasesTransform = {
77
+ id: "rename-this-aliases",
78
+ description: "Renames `var x = this` aliases to $thisRef (stable when unique) or thisRef/thisRef2/...",
79
+ scope: "file",
80
+ parallelizable: true,
81
+ transform(context) {
82
+ let nodesVisited = 0;
83
+ let transformationsApplied = 0;
84
+ for (const fileInfo of getFilesToProcess(context)) {
85
+ const group = new RenameGroup();
86
+ const exportedNames = collectExportedNames(fileInfo.ast.program);
87
+ traverse(fileInfo.ast, {
88
+ VariableDeclarator(path) {
89
+ nodesVisited++;
90
+ const { id, init } = path.node;
91
+ if (id.type !== "Identifier")
92
+ return;
93
+ if (init?.type !== "ThisExpression")
94
+ return;
95
+ const currentName = id.name;
96
+ if (isStableRenamed(currentName))
97
+ return;
98
+ const binding = path.scope.getBinding(currentName);
99
+ if (!binding)
100
+ return;
101
+ if (!binding.constant)
102
+ return;
103
+ if (binding.scope.block.type === "Program" &&
104
+ exportedNames.has(currentName)) {
105
+ return;
106
+ }
107
+ group.add({
108
+ scope: binding.scope,
109
+ currentName,
110
+ baseName: BASE_NAME,
111
+ });
112
+ },
113
+ });
114
+ transformationsApplied += group.apply();
115
+ }
116
+ return Promise.resolve({
117
+ nodesVisited,
118
+ transformationsApplied,
119
+ });
120
+ },
121
+ };
@@ -10,6 +10,7 @@ import { renameLoopIndexVariablesV2Transform } from "./rename-loop-index-variabl
10
10
  import { renameLoopIndexVariablesV3Transform } from "./rename-loop-index-variables-v3/rename-loop-index-variables-v3-transform.js";
11
11
  import { renamePromiseExecutorParametersTransform } from "./rename-promise-executor-parameters/rename-promise-executor-parameters-transform.js";
12
12
  import { renameReplaceChildParametersTransform } from "./rename-replace-child-parameters/rename-replace-child-parameters-transform.js";
13
+ import { renameThisAliasesTransform } from "./rename-this-aliases/rename-this-aliases-transform.js";
13
14
  import { renameTimeoutIdsTransform } from "./rename-timeout-ids/rename-timeout-ids-transform.js";
14
15
  import { renameUseReferenceGuardsTransform } from "./rename-use-reference-guards/rename-use-reference-guards-transform.js";
15
16
  import { renameUseReferenceGuardsV2Transform } from "./rename-use-reference-guards-v2/rename-use-reference-guards-v2-transform.js";
@@ -27,6 +28,7 @@ export const transformRegistry = {
27
28
  [renameLoopIndexVariablesV3Transform.id]: renameLoopIndexVariablesV3Transform,
28
29
  [renamePromiseExecutorParametersTransform.id]: renamePromiseExecutorParametersTransform,
29
30
  [renameReplaceChildParametersTransform.id]: renameReplaceChildParametersTransform,
31
+ [renameThisAliasesTransform.id]: renameThisAliasesTransform,
30
32
  [renameTimeoutIdsTransform.id]: renameTimeoutIdsTransform,
31
33
  [renameUseReferenceGuardsTransform.id]: renameUseReferenceGuardsTransform,
32
34
  [renameUseReferenceGuardsV2Transform.id]: renameUseReferenceGuardsV2Transform,
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.10.0",
5
+ "version": "1.11.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",
@@ -81,6 +81,16 @@
81
81
  "evaluatedAt": "2026-01-22T12:49:10.952Z",
82
82
  "notes": "Auto-added by evaluation script. Measured with baseline none: 0.09%."
83
83
  },
84
+ {
85
+ "id": "rename-this-aliases",
86
+ "description": "Renames `var x = this` aliases to $thisRef (stable when unique) or thisRef/thisRef2/...",
87
+ "scope": "file",
88
+ "parallelizable": true,
89
+ "diffReductionImpact": 0.00003774938185385768,
90
+ "recommended": true,
91
+ "evaluatedAt": "2026-01-23T17:57:26.908Z",
92
+ "notes": "Measured with baseline none: 0.00%. Improves readability by stabilizing `this` aliases used for closures."
93
+ },
84
94
  {
85
95
  "id": "expand-sequence-expressions-v4",
86
96
  "description": "Expands comma operator sequences in returns, throws, statements (including control-flow bodies), and variable initializers",
@@ -164,8 +174,8 @@
164
174
  ],
165
175
  "presetStats": {
166
176
  "recommended": {
167
- "diffReductionImpact": 0.0027273928389422997,
168
- "notes": "Measured with baseline none: 0.27%."
177
+ "diffReductionImpact": 0.003690002076215948,
178
+ "notes": "Measured with baseline none: 0.37%."
169
179
  }
170
180
  }
171
181
  }