-
Notifications
You must be signed in to change notification settings - Fork 618
/
Copy pathMinifiedIdentifier.ts
160 lines (145 loc) · 3.77 KB
/
MinifiedIdentifier.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
// TODO: Allow dynamic override of these values in the input to the minifier
import { IDENTIFIER_LEADING_DIGITS, IDENTIFIER_TRAILING_DIGITS } from './constants';
// Set of ECMAScript reserved keywords (past and present): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar
const RESERVED_KEYWORDS: string[] = [
'abstract',
'arguments',
'boolean',
'break',
'byte',
'case',
'catch',
'char',
'class',
'const',
'continue',
'debugger',
'default',
'delete',
'do',
'double',
'else',
'enum',
'export',
'extends',
'false',
'final',
'finally',
'float',
'for',
'function',
'get',
'goto',
'if',
'implements',
'import',
'in',
'instanceof',
'int',
'interface',
'let',
'long',
'native',
'new',
'null',
'package',
'private',
'protected',
'public',
'return',
'set',
'short',
'static',
'super',
'switch',
'synchronized',
'this',
'throw',
'throws',
'transient',
'true',
'try',
'typeof',
'var',
'void',
'volatile',
'while',
'with',
'yield'
];
/**
* Gets a base54 string suitable for use as a JavaScript identifier, not accounting for reserved keywords
* @param ordinal - The number to convert to a base54 identifier
*/
export function getIdentifierInternal(ordinal: number): string {
let ret: string = IDENTIFIER_LEADING_DIGITS[ordinal % 54];
ordinal = (ordinal / 54) | 0; // eslint-disable-line no-bitwise
while (ordinal > 0) {
--ordinal;
ret += IDENTIFIER_TRAILING_DIGITS[ordinal & 0x3f]; // eslint-disable-line no-bitwise
ordinal >>>= 6; // eslint-disable-line no-bitwise
}
return ret;
}
const leadingCharIndex: Map<number, number> = new Map();
for (let i: number = 0; i < 64; i++) {
leadingCharIndex.set(IDENTIFIER_LEADING_DIGITS.charCodeAt(i), i);
}
const trailingCharIndex: Map<number, number> = new Map();
for (let i: number = 0; i < 64; i++) {
trailingCharIndex.set(IDENTIFIER_TRAILING_DIGITS.charCodeAt(i), i);
}
/**
* Converts an identifier into the ordinal that would produce it, not accounting for reserved keywords
* Returns NaN if the result would exceed 31 bits
* @param identifier - The identifier to convert to a numeric value
*/
export function getOrdinalFromIdentifierInternal(identifier: string): number {
let ordinal: number = 0;
for (let i: number = identifier.length - 1; i > 0; i--) {
if (ordinal >= 0x2000000) {
return NaN;
}
ordinal <<= 6; // eslint-disable-line no-bitwise
ordinal += trailingCharIndex.get(identifier.charCodeAt(i))! + 1;
}
if (ordinal >= 0x2000000) {
return NaN;
}
ordinal *= 54;
ordinal += leadingCharIndex.get(identifier.charCodeAt(0))!;
return ordinal;
}
/**
* getIdentifier(n) would otherwise return each of these specified ECMAScript reserved keywords, which are not legal identifiers.
*/
const RESERVED_ORDINALS: number[] = ((): number[] => {
const reserved: number[] = [];
for (const keyword of RESERVED_KEYWORDS) {
const ordinal: number = getOrdinalFromIdentifierInternal(keyword);
if (!isNaN(ordinal)) {
reserved.push(ordinal);
}
}
return reserved.sort((x: number, y: number) => x - y);
})();
/**
* Gets a base54 string suitable for use as a JavaScript identifier, omitting those that are valid ECMAScript keywords
*
* @param ordinal - The number to convert to a base54 identifier
*
* @public
*/
export function getIdentifier(ordinal: number): string {
// Need to skip over reserved keywords
for (
let i: number = 0, len: number = RESERVED_ORDINALS.length;
i < len && ordinal >= RESERVED_ORDINALS[i];
i++
) {
++ordinal;
}
return getIdentifierInternal(ordinal);
}