@eliasku/ts-transformers 0.0.1
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.
- package/README.md +0 -0
- package/package.json +50 -0
- package/src/config.ts +1 -0
- package/src/const-enum/evaluator.ts +165 -0
- package/src/const-enum/index.ts +181 -0
- package/src/const-enum/registry.ts +169 -0
- package/src/const-enum/utils.ts +13 -0
- package/src/mangler/exports/tracker.ts +292 -0
- package/src/mangler/index.ts +642 -0
- package/src/mangler/types.ts +51 -0
- package/src/mangler/typescript-helpers.ts +204 -0
- package/src/mangler/utils/ast-utils.ts +7 -0
- package/src/mangler/utils/symbol-utils.ts +213 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
|
|
3
|
+
const namedDeclarationKinds = [
|
|
4
|
+
ts.SyntaxKind.InterfaceDeclaration,
|
|
5
|
+
ts.SyntaxKind.ClassDeclaration,
|
|
6
|
+
ts.SyntaxKind.EnumDeclaration,
|
|
7
|
+
ts.SyntaxKind.TypeAliasDeclaration,
|
|
8
|
+
ts.SyntaxKind.ModuleDeclaration,
|
|
9
|
+
ts.SyntaxKind.FunctionDeclaration,
|
|
10
|
+
ts.SyntaxKind.VariableDeclaration,
|
|
11
|
+
ts.SyntaxKind.PropertySignature,
|
|
12
|
+
ts.SyntaxKind.Parameter,
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
export const isNodeNamedDeclaration = (node: ts.Node): node is ts.NamedDeclaration =>
|
|
16
|
+
namedDeclarationKinds.indexOf(node.kind) !== -1;
|
|
17
|
+
|
|
18
|
+
export function getActualSymbol(symbol: ts.Symbol, typeChecker: ts.TypeChecker): ts.Symbol {
|
|
19
|
+
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
20
|
+
symbol = typeChecker.getAliasedSymbol(symbol);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return symbol;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function splitTransientSymbol(symbol: ts.Symbol, typeChecker: ts.TypeChecker): ts.Symbol[] {
|
|
27
|
+
// actually I think we even don't need to operate/use "Transient" symbols anywhere
|
|
28
|
+
// it's kind of aliased symbol, but just merged
|
|
29
|
+
// but it's hard to refractor everything to use array of symbols instead of just symbol
|
|
30
|
+
// so let's fix it for some places
|
|
31
|
+
if ((symbol.flags & ts.SymbolFlags.Transient) === 0) {
|
|
32
|
+
return [symbol];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// "Transient" symbol is kinda "merged" symbol
|
|
36
|
+
// I don't really know is this way to "split" is correct
|
|
37
|
+
// but it seems that it works for now ¯\_(ツ)_/¯
|
|
38
|
+
const declarations = getDeclarationsForSymbol(symbol);
|
|
39
|
+
const result: ts.Symbol[] = [];
|
|
40
|
+
for (const declaration of declarations) {
|
|
41
|
+
if (!isNodeNamedDeclaration(declaration) || declaration.name === undefined) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const sym = typeChecker.getSymbolAtLocation(declaration.name);
|
|
46
|
+
if (sym === undefined) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
result.push(getActualSymbol(sym, typeChecker));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function getDeclarationsForSymbol(symbol: ts.Symbol): ts.Declaration[] {
|
|
57
|
+
const result: ts.Declaration[] = [];
|
|
58
|
+
|
|
59
|
+
if (symbol.declarations !== undefined) {
|
|
60
|
+
result.push(...symbol.declarations);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (symbol.valueDeclaration !== undefined) {
|
|
64
|
+
// push valueDeclaration might be already in declarations array
|
|
65
|
+
// so let's check first to avoid duplication nodes
|
|
66
|
+
if (!result.includes(symbol.valueDeclaration)) {
|
|
67
|
+
result.push(symbol.valueDeclaration);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function getExportsForSourceFile(typeChecker: ts.TypeChecker, sourceFileSymbol: ts.Symbol): ts.Symbol[] {
|
|
75
|
+
if (sourceFileSymbol.exports !== undefined) {
|
|
76
|
+
const commonJsExport = sourceFileSymbol.exports.get(ts.InternalSymbolName.ExportEquals);
|
|
77
|
+
if (commonJsExport !== undefined) {
|
|
78
|
+
return [getActualSymbol(commonJsExport, typeChecker)];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const result: ts.Symbol[] = typeChecker.getExportsOfModule(sourceFileSymbol);
|
|
83
|
+
|
|
84
|
+
if (sourceFileSymbol.exports !== undefined) {
|
|
85
|
+
const defaultExportSymbol = sourceFileSymbol.exports.get(ts.InternalSymbolName.Default);
|
|
86
|
+
if (defaultExportSymbol !== undefined) {
|
|
87
|
+
if (!result.includes(defaultExportSymbol)) {
|
|
88
|
+
// it seems that default export is always returned by getExportsOfModule
|
|
89
|
+
// but let's add it to be sure add if there is no such export
|
|
90
|
+
result.push(defaultExportSymbol);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return result.map((symbol: ts.Symbol) => getActualSymbol(symbol, typeChecker));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export type ClassMember =
|
|
99
|
+
| ts.MethodDeclaration
|
|
100
|
+
| ts.PropertyDeclaration
|
|
101
|
+
| ts.GetAccessorDeclaration
|
|
102
|
+
| ts.SetAccessorDeclaration;
|
|
103
|
+
|
|
104
|
+
export const isClassMember = (node: ts.Node): node is ClassMember =>
|
|
105
|
+
ts.isMethodDeclaration(node) || ts.isPropertyDeclaration(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node);
|
|
106
|
+
|
|
107
|
+
export function getClassOfMemberSymbol(
|
|
108
|
+
nodeSymbol: ts.Symbol,
|
|
109
|
+
): ts.ClassLikeDeclaration | ts.ObjectLiteralExpression | ts.TypeLiteralNode | ts.InterfaceDeclaration | null {
|
|
110
|
+
const classMembers = getClassMemberDeclarations(nodeSymbol);
|
|
111
|
+
if (classMembers.length !== 0) {
|
|
112
|
+
// we need any member to get class' declaration
|
|
113
|
+
const classMember = classMembers[0];
|
|
114
|
+
if (isConstructorParameter(classMember)) {
|
|
115
|
+
return (classMember.parent as ts.ConstructorDeclaration).parent;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// we're sure that it is a class, not interface
|
|
119
|
+
return classMember.parent as ts.ClassLikeDeclaration | ts.ObjectLiteralExpression;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export const hasPrivateKeyword = (node: ClassMember | ts.ParameterDeclaration) =>
|
|
126
|
+
hasModifier(node, ts.SyntaxKind.PrivateKeyword);
|
|
127
|
+
|
|
128
|
+
function getModifiers(node: ts.Node): readonly ts.Modifier[] {
|
|
129
|
+
if (isBreakingTypeScriptApi(ts)) {
|
|
130
|
+
if (!ts.canHaveModifiers(node)) {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return ts.getModifiers(node) || [];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
138
|
+
// @ts-ignore
|
|
139
|
+
return node.modifiers || [];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export const hasModifier = (node: ts.Node, modifier: ts.SyntaxKind) =>
|
|
143
|
+
getModifiers(node).some((mod) => mod.kind === modifier);
|
|
144
|
+
|
|
145
|
+
function getDecorators(node: ts.Node): readonly unknown[] {
|
|
146
|
+
if (isBreakingTypeScriptApi(ts)) {
|
|
147
|
+
if (!ts.canHaveDecorators(node)) {
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return ts.getDecorators(node) || [];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
155
|
+
// @ts-ignore
|
|
156
|
+
return node.decorators || [];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export const hasDecorators = (node: ts.Node) => getDecorators(node).length !== 0;
|
|
160
|
+
|
|
161
|
+
export const isConstructorParameter = (node: ts.Node): node is ts.ParameterDeclaration =>
|
|
162
|
+
ts.isParameter(node) &&
|
|
163
|
+
ts.isConstructorDeclaration(node.parent as ts.Node) &&
|
|
164
|
+
(hasModifier(node, ts.SyntaxKind.PublicKeyword) ||
|
|
165
|
+
hasModifier(node, ts.SyntaxKind.ProtectedKeyword) ||
|
|
166
|
+
hasModifier(node, ts.SyntaxKind.PrivateKeyword) ||
|
|
167
|
+
hasModifier(node, ts.SyntaxKind.ReadonlyKeyword));
|
|
168
|
+
|
|
169
|
+
function getClassMemberDeclarations(symbol: ts.Symbol | undefined): (ClassMember | ts.ParameterDeclaration)[] {
|
|
170
|
+
if (symbol === undefined) {
|
|
171
|
+
return [];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const declarations = symbol.getDeclarations();
|
|
175
|
+
if (declarations === undefined) {
|
|
176
|
+
return [];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return declarations.filter((x: ts.Declaration): x is ClassMember | ts.ParameterDeclaration => {
|
|
180
|
+
return isClassMember(x) || isConstructorParameter(x);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export const isSymbolClassMember = (symbol: ts.Symbol | undefined) => getClassMemberDeclarations(symbol).length !== 0;
|
|
185
|
+
|
|
186
|
+
export const isPrivateClassMember = (symbol: ts.Symbol | undefined) =>
|
|
187
|
+
getClassMemberDeclarations(symbol).some(hasPrivateKeyword);
|
|
188
|
+
|
|
189
|
+
export function getNodeJSDocComment(node: ts.Node): string {
|
|
190
|
+
const start = node.getStart();
|
|
191
|
+
const jsDocStart = node.getStart(undefined, true);
|
|
192
|
+
return node.getSourceFile().getFullText().substring(jsDocStart, start).trim();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// decorators and modifiers-related api added in ts 4.8
|
|
196
|
+
interface BreakingTypeScriptApi {
|
|
197
|
+
canHaveDecorators(node: ts.Node): boolean;
|
|
198
|
+
getDecorators(node: ts.Node): readonly ts.Decorator[] | undefined;
|
|
199
|
+
canHaveModifiers(node: ts.Node): boolean;
|
|
200
|
+
getModifiers(node: ts.Node): readonly ts.Modifier[] | undefined;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const isBreakingTypeScriptApi = (compiler: object): compiler is BreakingTypeScriptApi =>
|
|
204
|
+
"canHaveDecorators" in compiler;
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
|
|
3
|
+
export function getActualSymbol(symbol: ts.Symbol, typeChecker: ts.TypeChecker): ts.Symbol {
|
|
4
|
+
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
5
|
+
symbol = typeChecker.getAliasedSymbol(symbol);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return symbol;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function splitTransientSymbol(symbol: ts.Symbol, typeChecker: ts.TypeChecker): ts.Symbol[] {
|
|
12
|
+
// actually I think we even don't need to operate/use "Transient" symbols anywhere
|
|
13
|
+
// it's kind of aliased symbol, but just merged
|
|
14
|
+
// but it's hard to refractor everything to use array of symbols instead of just symbol
|
|
15
|
+
// so let's fix it for some places
|
|
16
|
+
if ((symbol.flags & ts.SymbolFlags.Transient) === 0) {
|
|
17
|
+
return [symbol];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// "Transient" symbol is kinda "merged" symbol
|
|
21
|
+
// I don't really know is this way to "split" is correct
|
|
22
|
+
// but it seems that it works for now
|
|
23
|
+
const declarations = getDeclarationsForSymbol(symbol);
|
|
24
|
+
const result: ts.Symbol[] = [];
|
|
25
|
+
for (const declaration of declarations) {
|
|
26
|
+
if (!isNodeNamedDeclaration(declaration) || declaration.name === undefined) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const sym = typeChecker.getSymbolAtLocation(declaration.name);
|
|
31
|
+
if (sym === undefined) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
result.push(getActualSymbol(sym, typeChecker));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getDeclarationsForSymbol(symbol: ts.Symbol): ts.Declaration[] {
|
|
42
|
+
const result: ts.Declaration[] = [];
|
|
43
|
+
|
|
44
|
+
if (symbol.declarations !== undefined) {
|
|
45
|
+
result.push(...symbol.declarations);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (symbol.valueDeclaration !== undefined) {
|
|
49
|
+
// push valueDeclaration might be already in declarations array
|
|
50
|
+
// so let's check first to avoid duplication nodes
|
|
51
|
+
if (!result.includes(symbol.valueDeclaration)) {
|
|
52
|
+
result.push(symbol.valueDeclaration);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function getExportsForSourceFile(typeChecker: ts.TypeChecker, sourceFileSymbol: ts.Symbol): ts.Symbol[] {
|
|
60
|
+
if (sourceFileSymbol.exports !== undefined) {
|
|
61
|
+
const commonJsExport = sourceFileSymbol.exports.get(ts.InternalSymbolName.ExportEquals);
|
|
62
|
+
if (commonJsExport !== undefined) {
|
|
63
|
+
return [getActualSymbol(commonJsExport, typeChecker)];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const result: ts.Symbol[] = typeChecker.getExportsOfModule(sourceFileSymbol);
|
|
68
|
+
|
|
69
|
+
if (sourceFileSymbol.exports !== undefined) {
|
|
70
|
+
const defaultExportSymbol = sourceFileSymbol.exports.get(ts.InternalSymbolName.Default);
|
|
71
|
+
if (defaultExportSymbol !== undefined) {
|
|
72
|
+
if (!result.includes(defaultExportSymbol)) {
|
|
73
|
+
// it seems that default export is always returned by getExportsOfModule
|
|
74
|
+
// but let's add it to be sure add if there is no such export
|
|
75
|
+
result.push(defaultExportSymbol);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return result.map((symbol: ts.Symbol) => getActualSymbol(symbol, typeChecker));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const namedDeclarationKinds = [
|
|
84
|
+
ts.SyntaxKind.InterfaceDeclaration,
|
|
85
|
+
ts.SyntaxKind.ClassDeclaration,
|
|
86
|
+
ts.SyntaxKind.EnumDeclaration,
|
|
87
|
+
ts.SyntaxKind.TypeAliasDeclaration,
|
|
88
|
+
ts.SyntaxKind.ModuleDeclaration,
|
|
89
|
+
ts.SyntaxKind.FunctionDeclaration,
|
|
90
|
+
ts.SyntaxKind.VariableDeclaration,
|
|
91
|
+
ts.SyntaxKind.PropertySignature,
|
|
92
|
+
ts.SyntaxKind.Parameter,
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
export function isNodeNamedDeclaration(node: ts.Node): node is ts.NamedDeclaration {
|
|
96
|
+
return namedDeclarationKinds.indexOf(node.kind) !== -1;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export type ClassMember =
|
|
100
|
+
| ts.MethodDeclaration
|
|
101
|
+
| ts.PropertyDeclaration
|
|
102
|
+
| ts.GetAccessorDeclaration
|
|
103
|
+
| ts.SetAccessorDeclaration;
|
|
104
|
+
|
|
105
|
+
export function isClassMember(node: ts.Node): node is ClassMember {
|
|
106
|
+
return (
|
|
107
|
+
ts.isMethodDeclaration(node) || ts.isPropertyDeclaration(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node)
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function getClassOfMemberSymbol(
|
|
112
|
+
nodeSymbol: ts.Symbol,
|
|
113
|
+
): ts.ClassLikeDeclaration | ts.ObjectLiteralExpression | ts.TypeLiteralNode | ts.InterfaceDeclaration | null {
|
|
114
|
+
const classMembers = getClassMemberDeclarations(nodeSymbol);
|
|
115
|
+
if (classMembers.length !== 0) {
|
|
116
|
+
// we need any member to get class' declaration
|
|
117
|
+
const classMember = classMembers[0];
|
|
118
|
+
if (isConstructorParameter(classMember)) {
|
|
119
|
+
return (classMember.parent as ts.ConstructorDeclaration).parent;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// we're sure that it is a class, not interface
|
|
123
|
+
return classMember.parent as ts.ClassLikeDeclaration | ts.ObjectLiteralExpression;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function hasPrivateKeyword(node: ClassMember | ts.ParameterDeclaration): boolean {
|
|
130
|
+
return hasModifier(node, ts.SyntaxKind.PrivateKeyword);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function getModifiers(node: ts.Node): readonly ts.Modifier[] {
|
|
134
|
+
if (isBreakingTypeScriptApi(ts)) {
|
|
135
|
+
if (!ts.canHaveModifiers(node)) {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return ts.getModifiers(node) || [];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
143
|
+
// @ts-ignore
|
|
144
|
+
return node.modifiers || [];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function hasModifier(node: ts.Node, modifier: ts.SyntaxKind): boolean {
|
|
148
|
+
return getModifiers(node).some((mod) => mod.kind === modifier);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function getDecorators(node: ts.Node): readonly unknown[] {
|
|
152
|
+
if (isBreakingTypeScriptApi(ts)) {
|
|
153
|
+
if (!ts.canHaveDecorators(node)) {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return ts.getDecorators(node) || [];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
161
|
+
// @ts-ignore
|
|
162
|
+
return node.decorators || [];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function hasDecorators(node: ts.Node): boolean {
|
|
166
|
+
return getDecorators(node).length !== 0;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function isConstructorParameter(node: ts.Node): node is ts.ParameterDeclaration {
|
|
170
|
+
return (
|
|
171
|
+
ts.isParameter(node) &&
|
|
172
|
+
ts.isConstructorDeclaration(node.parent as ts.Node) &&
|
|
173
|
+
(hasModifier(node, ts.SyntaxKind.PublicKeyword) ||
|
|
174
|
+
hasModifier(node, ts.SyntaxKind.ProtectedKeyword) ||
|
|
175
|
+
hasModifier(node, ts.SyntaxKind.PrivateKeyword) ||
|
|
176
|
+
hasModifier(node, ts.SyntaxKind.ReadonlyKeyword))
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function getClassMemberDeclarations(symbol: ts.Symbol | undefined): (ClassMember | ts.ParameterDeclaration)[] {
|
|
181
|
+
if (symbol === undefined) {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const declarations = symbol.getDeclarations();
|
|
186
|
+
if (declarations === undefined) {
|
|
187
|
+
return [];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return declarations.filter((x: ts.Declaration): x is ClassMember | ts.ParameterDeclaration => {
|
|
191
|
+
return isClassMember(x) || isConstructorParameter(x);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function isSymbolClassMember(symbol: ts.Symbol | undefined): boolean {
|
|
196
|
+
return getClassMemberDeclarations(symbol).length !== 0;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function isPrivateClassMember(symbol: ts.Symbol | undefined): boolean {
|
|
200
|
+
return getClassMemberDeclarations(symbol).some(hasPrivateKeyword);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// decorators and modifiers-related api added in ts 4.8
|
|
204
|
+
interface BreakingTypeScriptApi {
|
|
205
|
+
canHaveDecorators(node: ts.Node): boolean;
|
|
206
|
+
getDecorators(node: ts.Node): readonly ts.Decorator[] | undefined;
|
|
207
|
+
canHaveModifiers(node: ts.Node): boolean;
|
|
208
|
+
getModifiers(node: ts.Node): readonly ts.Modifier[] | undefined;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function isBreakingTypeScriptApi(compiler: object): compiler is BreakingTypeScriptApi {
|
|
212
|
+
return "canHaveDecorators" in compiler;
|
|
213
|
+
}
|