Skip to content

Commit 2bcb317

Browse files
authored
Merge pull request #12 from graphemecluster/major-improvements-2
Major Improvements 2
2 parents e0ecdf2 + 24898be commit 2bcb317

33 files changed

+7571
-1552
lines changed

.vscode/launch.json

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"type": "node",
6+
"request": "launch",
7+
"name": "Build",
8+
"skipFiles": ["<node_internals>/**"],
9+
"program": "${workspaceFolder}/build/build.ts",
10+
"outFiles": ["${workspaceFolder}/dist/**/*.js"]
11+
}
12+
]
13+
}

build/alias.ts

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
const aliasArray: [string, string[]][] = [
2+
[
3+
"TypedNumberArray",
4+
[
5+
"Int8Array",
6+
"Uint8Array",
7+
"Uint8ClampedArray",
8+
"Int16Array",
9+
"Uint16Array",
10+
"Int32Array",
11+
"Uint32Array",
12+
"Float32Array",
13+
"Float64Array",
14+
],
15+
],
16+
["TypedBigIntArray", ["BigInt64Array", "BigUint64Array"]],
17+
];
18+
19+
export const alias = new Map(
20+
aliasArray.flatMap(([originalType, replacementTypes]) => [
21+
[
22+
originalType,
23+
new Map(
24+
replacementTypes.map((replacement) => [
25+
replacement,
26+
new Map([
27+
[originalType, replacement],
28+
[`${originalType}Constructor`, `${replacement}Constructor`],
29+
]),
30+
])
31+
),
32+
],
33+
[
34+
`${originalType}Constructor`,
35+
new Map(
36+
replacementTypes.map((replacement) => [
37+
`${replacement}Constructor`,
38+
new Map([
39+
[originalType, replacement],
40+
[`${originalType}Constructor`, `${replacement}Constructor`],
41+
]),
42+
])
43+
),
44+
],
45+
])
46+
);

build/logic/generate.ts

+88-45
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import path from "path";
22
import ts from "typescript";
3+
import { alias } from "../alias";
34
import { upsert } from "../util/upsert";
45
import { projectDir } from "./projectDir";
56

@@ -24,14 +25,10 @@ export function generate(
2425

2526
let result = "";
2627

27-
const replacementTargets = scanBetterFile(libFile);
28+
const replacementTargets = scanBetterFile(printer, libFile);
2829

2930
if (replacementTargets.size === 0) {
30-
for (const statement of originalFile.statements) {
31-
result += statement.getFullText(originalFile);
32-
}
33-
result += originalFile.text.slice(originalFile.endOfFileToken.pos);
34-
return result;
31+
return originalFile.text;
3532
}
3633

3734
const consumedReplacements = new Set<string>();
@@ -132,7 +129,7 @@ export function generate(
132129
},
133130
];
134131
});
135-
result += printInterface(printer, statement, memberList);
132+
result += printInterface(printer, statement, memberList, originalFile);
136133

137134
if (emitOriginalAsComment) {
138135
result += "\n";
@@ -188,7 +185,10 @@ type ReplacementTarget = (
188185
/**
189186
* Scan better lib file to determine which statements need to be replaced.
190187
*/
191-
function scanBetterFile(libFile: string): Map<string, ReplacementTarget[]> {
188+
function scanBetterFile(
189+
printer: ts.Printer,
190+
libFile: string
191+
): Map<string, ReplacementTarget[]> {
192192
const replacementTargets = new Map<string, ReplacementTarget[]>();
193193
{
194194
const betterLibFile = path.join(betterLibDir, `lib.${libFile}`);
@@ -198,43 +198,58 @@ function scanBetterFile(libFile: string): Map<string, ReplacementTarget[]> {
198198
// Scan better file to determine which statements need to be replaced.
199199
for (const statement of betterFile.statements) {
200200
const name = getStatementDeclName(statement) ?? "";
201-
if (ts.isInterfaceDeclaration(statement)) {
202-
const members = new Map<
203-
string,
204-
{
205-
member: ts.TypeElement;
206-
text: string;
207-
}[]
208-
>();
209-
for (const member of statement.members) {
210-
const memberName = member.name?.getText(betterFile) ?? "";
211-
upsert(members, memberName, (members = []) => {
212-
members.push({
213-
member,
214-
text: member.getFullText(betterFile),
201+
const aliasesMap =
202+
alias.get(name) ?? new Map([[name, new Map<string, string>()]]);
203+
for (const [targetName, typeMap] of aliasesMap) {
204+
const transformedStatement = replaceAliases(statement, typeMap);
205+
if (ts.isInterfaceDeclaration(transformedStatement)) {
206+
const members = new Map<
207+
string,
208+
{
209+
member: ts.TypeElement;
210+
text: string;
211+
}[]
212+
>();
213+
for (const member of transformedStatement.members) {
214+
const memberName = member.name?.getText(betterFile) ?? "";
215+
upsert(members, memberName, (members = []) => {
216+
const leadingSpacesMatch = /^\s*/.exec(
217+
member.getFullText(betterFile)
218+
);
219+
const leadingSpaces =
220+
leadingSpacesMatch !== null ? leadingSpacesMatch[0] : "";
221+
members.push({
222+
member,
223+
text:
224+
leadingSpaces +
225+
printer.printNode(
226+
ts.EmitHint.Unspecified,
227+
member,
228+
betterFile
229+
),
230+
});
231+
return members;
215232
});
216-
return members;
217-
});
218-
}
219-
220-
upsert(replacementTargets, name, (targets = []) => {
221-
targets.push({
222-
type: "interface",
223-
members,
224-
originalStatement: statement,
225-
sourceFile: betterFile,
233+
}
234+
upsert(replacementTargets, targetName, (targets = []) => {
235+
targets.push({
236+
type: "interface",
237+
members,
238+
originalStatement: transformedStatement,
239+
sourceFile: betterFile,
240+
});
241+
return targets;
226242
});
227-
return targets;
228-
});
229-
} else {
230-
upsert(replacementTargets, name, (statements = []) => {
231-
statements.push({
232-
type: "non-interface",
233-
statement,
234-
sourceFile: betterFile,
243+
} else {
244+
upsert(replacementTargets, targetName, (statements = []) => {
245+
statements.push({
246+
type: "non-interface",
247+
statement: transformedStatement,
248+
sourceFile: betterFile,
249+
});
250+
return statements;
235251
});
236-
return statements;
237-
});
252+
}
238253
}
239254
}
240255
}
@@ -308,10 +323,12 @@ function isPartialReplacement(
308323
function printInterface(
309324
printer: ts.Printer,
310325
originalNode: ts.InterfaceDeclaration,
311-
members: readonly { text: string }[]
326+
members: readonly { text: string }[],
327+
originalSourceFile: ts.SourceFile
312328
): string {
313-
const originalSourceFile = originalNode.getSourceFile();
314-
let result = "";
329+
let result = originalNode
330+
.getFullText(originalSourceFile)
331+
.slice(0, originalNode.getLeadingTriviaWidth(originalSourceFile));
315332
for (const dec of originalNode.decorators ?? []) {
316333
result += printer.printNode(
317334
ts.EmitHint.Unspecified,
@@ -372,3 +389,29 @@ function commentOut(code: string): string {
372389
const result = lines.map((line) => `// ${line}`);
373390
return result.join("\n") + "\n";
374391
}
392+
393+
function replaceAliases(
394+
statement: ts.Statement,
395+
typeMap: Map<string, string>
396+
): ts.Statement {
397+
if (typeMap.size === 0) return statement;
398+
return ts.transform(statement, [
399+
(context) => (sourceStatement) => {
400+
const visitor = (node: ts.Node): ts.Node => {
401+
if (ts.isTypeReferenceNode(node) && ts.isIdentifier(node.typeName)) {
402+
const replacementType = typeMap.get(node.typeName.text);
403+
if (replacementType === undefined) {
404+
return node;
405+
}
406+
return ts.factory.updateTypeReferenceNode(
407+
node,
408+
ts.factory.createIdentifier(replacementType),
409+
node.typeArguments
410+
);
411+
}
412+
return ts.visitEachChild(node, visitor, context);
413+
};
414+
return ts.visitNode(sourceStatement, visitor);
415+
},
416+
]).transformed[0];
417+
}

docs/diff.md

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ The following files are improved in better-typescript-lib:
1515
- [es2018.asyncgenerator.d.ts](./diff/es2018.asyncgenerator.d.ts.md)
1616
- [es2018.asynciterable.d.ts](./diff/es2018.asynciterable.d.ts.md)
1717
- [es2019.object.d.ts](./diff/es2019.object.d.ts.md)
18+
- [es2020.bigint.d.ts](./diff/es2020.bigint.d.ts.md)
1819
- [es2021.promise.d.ts](./diff/es2021.promise.d.ts.md)
1920
- [es2021.string.d.ts](./diff/es2021.string.d.ts.md)
2021
- [es2022.object.d.ts](./diff/es2022.object.d.ts.md)

docs/diff/es2015.collection.d.ts.md

+12-14
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,46 @@ Index: es2015.collection.d.ts
55
===================================================================
66
--- es2015.collection.d.ts
77
+++ es2015.collection.d.ts
8-
@@ -1,28 +1,25 @@
8+
@@ -1,28 +1,27 @@
99
interface Map<K, V> {
1010
clear(): void;
1111
delete(key: K): boolean;
1212
- forEach(
1313
- callbackfn: (value: V, key: K, map: Map<K, V>) => void,
1414
- thisArg?: any
1515
+ forEach<This = undefined>(
16-
+ callbackfn: (this: This, value: V, key: K, map: Map<K, V>) => void,
16+
+ callbackfn: (this: This, value: V, key: K, map: this) => void,
1717
+ thisArg?: This
1818
): void;
1919
get(key: K): V | undefined;
2020
has(key: K): boolean;
2121
set(key: K, value: V): this;
2222
readonly size: number;
2323
}
24-
-
24+
2525
interface MapConstructor {
2626
- new (): Map<any, any>;
2727
new <K, V>(entries?: readonly (readonly [K, V])[] | null): Map<K, V>;
2828
- readonly prototype: Map<any, any>;
2929
+ readonly prototype: Map<unknown, unknown>;
3030
}
3131
declare var Map: MapConstructor;
32-
-
32+
3333
interface ReadonlyMap<K, V> {
3434
- forEach(
3535
- callbackfn: (value: V, key: K, map: ReadonlyMap<K, V>) => void,
3636
- thisArg?: any
3737
+ forEach<This = undefined>(
38-
+ callbackfn: (this: This, value: V, key: K, map: ReadonlyMap<K, V>) => void,
38+
+ callbackfn: (this: This, value: V, key: K, map: this) => void,
3939
+ thisArg?: This
4040
): void;
4141
get(key: K): V | undefined;
4242
has(key: K): boolean;
4343
readonly size: number;
44-
@@ -33,39 +30,35 @@
45-
get(key: K): V | undefined;
46-
has(key: K): boolean;
44+
@@ -35,37 +34,37 @@
4745
set(key: K, value: V): this;
4846
}
49-
-
47+
5048
interface WeakMapConstructor {
5149
- new <K extends object = object, V = any>(
5250
- entries?: readonly [K, V][] | null
@@ -57,7 +55,7 @@ Index: es2015.collection.d.ts
5755
+ readonly prototype: WeakMap<object, unknown>;
5856
}
5957
declare var WeakMap: WeakMapConstructor;
60-
-
58+
6159
interface Set<T> {
6260
add(value: T): this;
6361
clear(): void;
@@ -66,27 +64,27 @@ Index: es2015.collection.d.ts
6664
- callbackfn: (value: T, value2: T, set: Set<T>) => void,
6765
- thisArg?: any
6866
+ forEach<This = undefined>(
69-
+ callbackfn: (this: This, value: T, value2: T, set: Set<T>) => void,
67+
+ callbackfn: (this: This, value: T, value2: T, set: this) => void,
7068
+ thisArg?: This
7169
): void;
7270
has(value: T): boolean;
7371
readonly size: number;
7472
}
75-
-
73+
7674
interface SetConstructor {
7775
- new <T = any>(values?: readonly T[] | null): Set<T>;
7876
- readonly prototype: Set<any>;
7977
+ new <T>(values?: readonly T[] | null): Set<T>;
8078
+ readonly prototype: Set<unknown>;
8179
}
8280
declare var Set: SetConstructor;
83-
-
81+
8482
interface ReadonlySet<T> {
8583
- forEach(
8684
- callbackfn: (value: T, value2: T, set: ReadonlySet<T>) => void,
8785
- thisArg?: any
8886
+ forEach<This = undefined>(
89-
+ callbackfn: (this: This, value: T, value2: T, set: ReadonlySet<T>) => void,
87+
+ callbackfn: (this: This, value: T, value2: T, set: this) => void,
9088
+ thisArg?: This
9189
): void;
9290
has(value: T): boolean;

0 commit comments

Comments
 (0)