@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.
@@ -0,0 +1,642 @@
1
+ import ts from "typescript";
2
+
3
+ import { ExportsSymbolTree } from "./exports/tracker";
4
+ import {
5
+ getDeclarationsForSymbol,
6
+ isClassMember,
7
+ isConstructorParameter,
8
+ isPrivateClassMember,
9
+ isSymbolClassMember,
10
+ getClassOfMemberSymbol,
11
+ hasDecorators,
12
+ hasModifier,
13
+ splitTransientSymbol,
14
+ isNodeNamedDeclaration,
15
+ } from "./utils/symbol-utils";
16
+ import { getNodeJSDocComment } from "./utils/ast-utils";
17
+ import { RenameOptions, defaultOptions, VisibilityType } from "./types";
18
+ import { LOGS } from "../config";
19
+
20
+ export function propertiesRenameTransformer(
21
+ program: ts.Program,
22
+ config?: Partial<RenameOptions>,
23
+ ): ts.TransformerFactory<ts.SourceFile> {
24
+ return createTransformerFactory(program, config);
25
+ }
26
+
27
+ function createTransformerFactory(
28
+ program: ts.Program,
29
+ options?: Partial<RenameOptions>,
30
+ ): ts.TransformerFactory<ts.SourceFile> {
31
+ const fullOptions: RenameOptions = { ...defaultOptions, ...options };
32
+ const typeChecker = program.getTypeChecker();
33
+ const exportsSymbolTree = new ExportsSymbolTree(program, fullOptions.entrySourceFiles);
34
+
35
+ const cache = new Map<ts.Symbol, VisibilityType>();
36
+
37
+ function putToCache(nodeSymbol: ts.Symbol, val: VisibilityType): VisibilityType {
38
+ cache.set(nodeSymbol, val);
39
+ return val;
40
+ }
41
+
42
+ return (context: ts.TransformationContext) => {
43
+ function transformNodeAndChildren(node: ts.SourceFile, ctx: ts.TransformationContext): ts.SourceFile;
44
+ function transformNodeAndChildren(node: ts.Node, ctx: ts.TransformationContext): ts.Node;
45
+ function transformNodeAndChildren(node: ts.Node, ctx: ts.TransformationContext): ts.Node {
46
+ return ts.visitEachChild(
47
+ transformNode(node),
48
+ (childNode: ts.Node) => transformNodeAndChildren(childNode, ctx),
49
+ ctx,
50
+ );
51
+ }
52
+
53
+ function transformNode(node: ts.Node): ts.Node {
54
+ // const a = { node }
55
+ if (ts.isShorthandPropertyAssignment(node)) {
56
+ return handleShorthandPropertyAssignment(node);
57
+ }
58
+
59
+ // const { node } = obj;
60
+ if (ts.isBindingElement(node) && node.propertyName === undefined) {
61
+ if (node.parent && ts.isObjectBindingPattern(node.parent)) {
62
+ return handleShorthandObjectBindingElement(node);
63
+ } else {
64
+ console.warn("!!!", node);
65
+ }
66
+ }
67
+
68
+ // is not supported:
69
+ // const { node = default_Value } = obj;
70
+
71
+ // 'node' in obj
72
+ if (
73
+ node.parent &&
74
+ ts.isStringLiteral(node) &&
75
+ ts.isBinaryExpression(node.parent) &&
76
+ node.parent.operatorToken.kind === ts.SyntaxKind.InKeyword
77
+ ) {
78
+ return handleInKeyword(node);
79
+ }
80
+
81
+ if (ts.isIdentifier(node) && node.parent) {
82
+ // obj.node
83
+ if (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) {
84
+ return handlePropertyAccessIdentifier(node);
85
+ }
86
+
87
+ // private node
88
+ // public node()
89
+ if (isClassMember(node.parent) && node.parent.name === node) {
90
+ return handleClassMember(node);
91
+ }
92
+
93
+ // enum Enum { node }
94
+ if (ts.isEnumMember(node.parent) && node.parent.name === node) {
95
+ return handleEnumMember(node);
96
+ }
97
+
98
+ // const a = { node: 123 }
99
+ if (ts.isPropertyAssignment(node.parent) && node.parent.name === node) {
100
+ return handlePropertyAssignment(node);
101
+ }
102
+
103
+ // const { node: localName } = obj;
104
+ if (ts.isBindingElement(node.parent) && node.parent.propertyName === node) {
105
+ return handleBindingElement(node);
106
+ }
107
+
108
+ // <Comp node={...} />
109
+ if (ts.isJsxAttribute(node.parent) && node.parent.name === node) {
110
+ return handleJsxAttributeName(node);
111
+ }
112
+
113
+ // constructor(public node: string) { // <--- this
114
+ // console.log(node); // <--- and this
115
+ // }
116
+ if (
117
+ (isConstructorParameter(node.parent) && node.parent.name === node) ||
118
+ isConstructorParameterReference(node)
119
+ ) {
120
+ return handleCtorParameter(node);
121
+ }
122
+ }
123
+
124
+ // obj['fooBar']
125
+ if (
126
+ node.parent &&
127
+ ts.isStringLiteral(node) &&
128
+ ts.isElementAccessExpression(node.parent) &&
129
+ node.parent.argumentExpression === node
130
+ ) {
131
+ return handleElementAccessExpression(node);
132
+ }
133
+
134
+ return node;
135
+ }
136
+
137
+ function handleInKeyword(node: ts.StringLiteral): ts.StringLiteral {
138
+ const parent = node.parent as ts.BinaryExpression;
139
+ const nodeType = typeChecker.getTypeAtLocation(node);
140
+ if (!nodeType.isStringLiteral()) {
141
+ throw new Error(`Can't get type for left expression in ${node.parent.getText()}`);
142
+ }
143
+
144
+ const propertyName = nodeType.value;
145
+ if (isTypePropertyExternal(typeChecker.getTypeAtLocation(parent.right), propertyName)) {
146
+ return node;
147
+ }
148
+
149
+ return createNewNode(propertyName, VisibilityType.Internal, context.factory.createStringLiteral);
150
+ }
151
+
152
+ // obj.node
153
+ function handlePropertyAccessIdentifier(node: ts.Identifier): ts.Identifier {
154
+ return createNewIdentifier(node);
155
+ }
156
+
157
+ // obj['fooBar']
158
+ function handleElementAccessExpression(node: ts.StringLiteral): ts.StringLiteral {
159
+ const visibilityType = getNodeVisibilityType(node);
160
+ if (visibilityType === VisibilityType.External) {
161
+ return node;
162
+ }
163
+
164
+ return createNewNodeFromProperty(node, visibilityType, context.factory.createStringLiteral);
165
+ }
166
+
167
+ // private node
168
+ // public node()
169
+ function handleClassMember(node: ts.Identifier): ts.Identifier {
170
+ return createNewIdentifier(node);
171
+ }
172
+
173
+ // enum Enum { node }
174
+ function handleEnumMember(node: ts.Identifier): ts.Identifier {
175
+ return createNewIdentifier(node);
176
+ }
177
+
178
+ // const { node: localName } = obj;
179
+ function handleBindingElement(node: ts.Identifier): ts.Identifier {
180
+ return createNewIdentifier(node);
181
+ }
182
+
183
+ // <Comp node={...} />
184
+ function handleJsxAttributeName(node: ts.Identifier): ts.Identifier {
185
+ return createNewIdentifier(node);
186
+ }
187
+
188
+ // const a = { node: 123 }
189
+ function handlePropertyAssignment(node: ts.Identifier): ts.Identifier {
190
+ return createNewIdentifier(node);
191
+ }
192
+
193
+ // const a = { node }
194
+ function handleShorthandPropertyAssignment(
195
+ node: ts.ShorthandPropertyAssignment,
196
+ ): ts.PropertyAssignment | ts.ShorthandPropertyAssignment {
197
+ const visibilityType = getNodeVisibilityType(node.name);
198
+ if (visibilityType === VisibilityType.External) {
199
+ return node;
200
+ }
201
+
202
+ return createNewNodeFromProperty(node.name, visibilityType, (newName: string) => {
203
+ return context.factory.createPropertyAssignment(newName, node.name);
204
+ });
205
+ }
206
+
207
+ // const { node } = obj;
208
+ function handleShorthandObjectBindingElement(node: ts.BindingElement): ts.BindingElement {
209
+ if (!ts.isIdentifier(node.name)) {
210
+ return node;
211
+ }
212
+
213
+ const visibilityType = getNodeVisibilityType(node);
214
+ if (visibilityType === VisibilityType.External) {
215
+ return node;
216
+ }
217
+
218
+ return createNewNodeFromProperty(node.name, visibilityType, (newName: string) => {
219
+ return context.factory.createBindingElement(node.dotDotDotToken, newName, node.name, node.initializer);
220
+ });
221
+ }
222
+
223
+ // constructor(public node: string) { // <--- this
224
+ // console.log(node); // <--- and this
225
+ // }
226
+ function handleCtorParameter(node: ts.Identifier): ts.Identifier {
227
+ return createNewIdentifier(node);
228
+ }
229
+
230
+ function createNewIdentifier(oldIdentifier: ts.Identifier): ts.Identifier {
231
+ const visibilityType = getNodeVisibilityType(oldIdentifier);
232
+ if (visibilityType === VisibilityType.External) {
233
+ return oldIdentifier;
234
+ }
235
+
236
+ return createNewNodeFromProperty(oldIdentifier, visibilityType, context.factory.createIdentifier);
237
+ }
238
+
239
+ function createNewNodeFromProperty<T extends ts.Node>(
240
+ oldProperty: ts.PropertyName,
241
+ type: VisibilityType,
242
+ createNode: (newName: string) => T,
243
+ ): T {
244
+ const symbol = typeChecker.getSymbolAtLocation(oldProperty);
245
+ if (symbol === undefined) {
246
+ throw new Error(`Cannot get symbol for node "${oldProperty.getText()}"`);
247
+ }
248
+
249
+ const oldPropertyName = ts.unescapeLeadingUnderscores(symbol.escapedName);
250
+
251
+ return createNewNode(oldPropertyName, type, createNode);
252
+ }
253
+
254
+ function createNewNode<T extends ts.Node>(
255
+ oldPropertyName: string,
256
+ type: VisibilityType,
257
+ createNode: (newName: string) => T,
258
+ ): T {
259
+ const newPropertyName = getNewName(oldPropertyName, type);
260
+ return createNode(newPropertyName);
261
+ }
262
+
263
+ function getNewName(originalName: string, type: VisibilityType): string {
264
+ return `${
265
+ type === VisibilityType.Private ? fullOptions.privatePrefix : fullOptions.internalPrefix
266
+ }${originalName}`;
267
+ }
268
+
269
+ function getActualSymbol(symbol: ts.Symbol): ts.Symbol {
270
+ if (symbol.flags & ts.SymbolFlags.Alias) {
271
+ symbol = typeChecker.getAliasedSymbol(symbol);
272
+ }
273
+
274
+ return symbol;
275
+ }
276
+
277
+ function getNodeSymbol(node: ts.Expression | ts.NamedDeclaration | ts.DeclarationName): ts.Symbol | null {
278
+ const symbol = typeChecker.getSymbolAtLocation(node);
279
+ if (symbol === undefined) {
280
+ return null;
281
+ }
282
+
283
+ return getActualSymbol(symbol);
284
+ }
285
+
286
+ function isTypePropertyExternal(type: ts.Type, typePropertyName: string): boolean {
287
+ // if a type is unknown or any - they should be interpret as a public ones
288
+ if (type.flags & ts.TypeFlags.Unknown || type.flags & ts.TypeFlags.Any) {
289
+ return true;
290
+ }
291
+
292
+ if (type.flags & ts.TypeFlags.IndexedAccess) {
293
+ return isTypePropertyExternal(typeChecker.getApparentType(type), typePropertyName);
294
+ }
295
+
296
+ const symbol = type.getSymbol();
297
+ const propertySymbol = typeChecker.getPropertyOfType(type, typePropertyName);
298
+
299
+ if (type.flags & ts.TypeFlags.Object) {
300
+ const objectType = type as ts.ObjectType;
301
+
302
+ // treat any tuple property as "external"
303
+ if (objectType.objectFlags & ts.ObjectFlags.Tuple) {
304
+ return true;
305
+ }
306
+
307
+ if (objectType.objectFlags & ts.ObjectFlags.Reference) {
308
+ const target = (objectType as ts.TypeReference).target;
309
+ if (target !== objectType && isTypePropertyExternal(target, typePropertyName)) {
310
+ return true;
311
+ }
312
+ }
313
+
314
+ // in case when we can't get where a property come from in mapped types
315
+ // let's check the whole type explicitly
316
+ // thus in case of when property doesn't have a declaration let's treat any property of a mapped type as "external" if its parent type is external
317
+ // e.g. Readonly<Foo>.field will look for `field` in _Foo_ type (not in Readonly<Foo>), but { [K in 'foo' | 'bar']: any } won't
318
+ // perhaps it would be awesome to handle exactly property we have, but ¯\_(ツ)_/¯
319
+ const propertyHasDeclarations =
320
+ propertySymbol !== undefined ? getDeclarationsForSymbol(propertySymbol).length !== 0 : false;
321
+ if (
322
+ objectType.objectFlags & ts.ObjectFlags.Mapped &&
323
+ symbol !== undefined &&
324
+ !propertyHasDeclarations &&
325
+ getSymbolVisibilityType(symbol) === VisibilityType.External
326
+ ) {
327
+ return true;
328
+ }
329
+ }
330
+
331
+ if (type.isUnionOrIntersection()) {
332
+ const hasExternalSubType = type.types.some((t: ts.Type) => isTypePropertyExternal(t, typePropertyName));
333
+ if (hasExternalSubType) {
334
+ return hasExternalSubType;
335
+ }
336
+ }
337
+
338
+ if (symbol !== undefined) {
339
+ const declarations = getDeclarationsForSymbol(symbol);
340
+ for (const declaration of declarations) {
341
+ if (
342
+ (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration)) &&
343
+ declaration.heritageClauses !== undefined
344
+ ) {
345
+ const hasHeritageClausesExternals = declaration.heritageClauses.some((clause: ts.HeritageClause) => {
346
+ return clause.types.some((expr: ts.ExpressionWithTypeArguments) => {
347
+ return isTypePropertyExternal(typeChecker.getTypeAtLocation(expr), typePropertyName);
348
+ });
349
+ });
350
+
351
+ if (hasHeritageClausesExternals) {
352
+ return true;
353
+ }
354
+ }
355
+ }
356
+ }
357
+
358
+ if (propertySymbol === undefined) {
359
+ return false;
360
+ }
361
+
362
+ return [propertySymbol, ...splitTransientSymbol(propertySymbol, typeChecker)].some(
363
+ (sym: ts.Symbol) => getSymbolVisibilityType(sym) === VisibilityType.External,
364
+ );
365
+ }
366
+
367
+ function getNodeVisibilityType(
368
+ node: ts.Expression | ts.Identifier | ts.StringLiteral | ts.BindingElement,
369
+ ): VisibilityType {
370
+ if (ts.isPropertyAssignment(node.parent) || ts.isShorthandPropertyAssignment(node.parent)) {
371
+ let expressionToGetTypeFrom: ts.Expression = node.parent.parent;
372
+ let lastKnownExpression: ts.AsExpression | ts.ObjectLiteralExpression = node.parent.parent;
373
+ let currentNode: ts.Node = node.parent.parent.parent;
374
+
375
+ while (ts.isParenthesizedExpression(currentNode) || ts.isAsExpression(currentNode)) {
376
+ if (ts.isAsExpression(currentNode)) {
377
+ expressionToGetTypeFrom = lastKnownExpression;
378
+ lastKnownExpression = currentNode;
379
+ }
380
+
381
+ currentNode = currentNode.parent;
382
+ }
383
+
384
+ // to get correct contextual type we need to provide the previous last expression rather than the last one
385
+ const type = typeChecker.getContextualType(expressionToGetTypeFrom);
386
+ if (type !== undefined && isTypePropertyExternal(type, node.getText())) {
387
+ return VisibilityType.External;
388
+ }
389
+ }
390
+
391
+ if (ts.isPropertyAccessExpression(node.parent) || ts.isElementAccessExpression(node.parent)) {
392
+ if (ts.isIdentifier(node.parent.expression)) {
393
+ const expressionSymbol = typeChecker.getSymbolAtLocation(node.parent.expression);
394
+ if (LOGS) {
395
+ console.log(
396
+ `[transformer] PropertyAccess: expression=${node.parent.expression.getText()}, property=${node.getText()}`,
397
+ );
398
+ console.log(`[transformer] Expression symbol: ${expressionSymbol?.name}`);
399
+ }
400
+ if (expressionSymbol !== undefined) {
401
+ // import * as foo from '...';
402
+ // foo.node;
403
+ // foo['node'];
404
+ // or
405
+ // namespace Foo { ... }
406
+ // Foo.node
407
+ // Foo['node'];
408
+ const declarations = getDeclarationsForSymbol(expressionSymbol);
409
+ if (LOGS) {
410
+ console.log(`[transformer] Declarations: ${declarations.map((d) => ts.SyntaxKind[d.kind]).join(", ")}`);
411
+ }
412
+ const isModuleOrStarImport = declarations.some(
413
+ (decl: ts.Declaration) => ts.isNamespaceImport(decl) || ts.isModuleDeclaration(decl),
414
+ );
415
+ if (LOGS) {
416
+ console.log(`[transformer] isModuleOrStarImport: ${isModuleOrStarImport}`);
417
+ }
418
+ if (isModuleOrStarImport) {
419
+ // treat accessing to import-star or namespace as external one
420
+ // because we can't rename them yet
421
+ if (LOGS) {
422
+ console.log(`[transformer] Returning External (module/star import)`);
423
+ }
424
+ return VisibilityType.External;
425
+ }
426
+
427
+ // import { foo } from '...';
428
+ // where foo is a namespace re-export (export * as foo from './bar')
429
+ // In this case, symbol for 'foo' is an alias to a module
430
+ // Check if the symbol's type is a namespace module or regular module
431
+ const hasImportSpecifier = declarations.some((decl) => ts.isImportSpecifier(decl));
432
+ if (LOGS) {
433
+ console.log(`[transformer] hasImportSpecifier: ${hasImportSpecifier}`);
434
+ }
435
+ if (hasImportSpecifier) {
436
+ const expressionType = typeChecker.getTypeAtLocation(node.parent.expression);
437
+ if (LOGS) {
438
+ console.log(`[transformer] Expression type: ${expressionType?.flags}`);
439
+ }
440
+ if (expressionType) {
441
+ const typeSymbol = expressionType.getSymbol();
442
+ if (LOGS) {
443
+ console.log(`[transformer] Type symbol: ${typeSymbol?.name}, flags: ${typeSymbol?.flags}`);
444
+ }
445
+ // Check if it's a module (NamespaceModule or regular Module)
446
+ // NamespaceModule: 0x8000000, Module: 0x200
447
+ const isModule =
448
+ typeSymbol &&
449
+ ((typeSymbol.flags & ts.SymbolFlags.NamespaceModule) !== 0 ||
450
+ (typeSymbol.flags & ts.SymbolFlags.Module) !== 0);
451
+ if (isModule) {
452
+ // The expression's type is a module, so accessing its properties
453
+ // means accessing exports from that module, which are external
454
+ if (LOGS) {
455
+ console.log(`[transformer] Returning External (module)`);
456
+ }
457
+ return VisibilityType.External;
458
+ }
459
+ }
460
+ }
461
+ }
462
+ }
463
+
464
+ const expressionType = typeChecker.getTypeAtLocation(node.parent.expression);
465
+ const propertyText = node.getText();
466
+ if (LOGS) {
467
+ console.log(`[transformer] Checking isTypePropertyExternal for ${propertyText}`);
468
+ }
469
+ if (isTypePropertyExternal(expressionType, propertyText)) {
470
+ if (LOGS) {
471
+ console.log(`[transformer] Returning External (isTypePropertyExternal)`);
472
+ }
473
+ return VisibilityType.External;
474
+ }
475
+ }
476
+
477
+ // shorthand binding element
478
+ // const { node } = obj;
479
+ if (
480
+ ts.isBindingElement(node) &&
481
+ isTypePropertyExternal(typeChecker.getTypeAtLocation(node.parent), node.getText())
482
+ ) {
483
+ return VisibilityType.External;
484
+ }
485
+
486
+ // full binding element
487
+ // const { node: propName } = obj;
488
+ if (
489
+ ts.isBindingElement(node.parent) &&
490
+ isTypePropertyExternal(typeChecker.getTypeAtLocation(node.parent.parent), node.getText())
491
+ ) {
492
+ return VisibilityType.External;
493
+ }
494
+
495
+ // <Comp node={...} />
496
+ if (ts.isJsxAttribute(node.parent)) {
497
+ const jsxTagSymbol = typeChecker.getSymbolAtLocation(node.parent.parent.parent.tagName);
498
+ if (jsxTagSymbol !== undefined && jsxTagSymbol.valueDeclaration !== undefined) {
499
+ const jsxPropsType = typeChecker.getTypeOfSymbolAtLocation(jsxTagSymbol, jsxTagSymbol.valueDeclaration);
500
+ if (isTypePropertyExternal(jsxPropsType, node.getText())) {
501
+ return VisibilityType.External;
502
+ }
503
+ }
504
+ }
505
+
506
+ const nodeSymbol = getNodeSymbol(node);
507
+ const classOfMember = nodeSymbol !== null ? getClassOfMemberSymbol(nodeSymbol) : null;
508
+ if (
509
+ classOfMember !== null &&
510
+ isTypePropertyExternal(typeChecker.getTypeAtLocation(classOfMember), node.getText())
511
+ ) {
512
+ return VisibilityType.External;
513
+ }
514
+
515
+ const symbol = ts.isBindingElement(node) ? getShorthandObjectBindingElementSymbol(node) : nodeSymbol;
516
+ if (symbol === null) {
517
+ return VisibilityType.External;
518
+ }
519
+
520
+ return getSymbolVisibilityType(symbol);
521
+ }
522
+
523
+ function getSymbolVisibilityType(nodeSymbol: ts.Symbol): VisibilityType {
524
+ nodeSymbol = getActualSymbol(nodeSymbol);
525
+
526
+ const cachedValue = cache.get(nodeSymbol);
527
+ if (cachedValue !== undefined) {
528
+ return cachedValue;
529
+ }
530
+
531
+ const symbolDeclarations = getDeclarationsForSymbol(nodeSymbol);
532
+ if (symbolDeclarations.some(isDeclarationFromExternals)) {
533
+ return putToCache(nodeSymbol, VisibilityType.External);
534
+ }
535
+
536
+ if (symbolDeclarations.some((decl: ts.Declaration) => hasModifier(decl, ts.SyntaxKind.DeclareKeyword))) {
537
+ return putToCache(nodeSymbol, VisibilityType.External);
538
+ }
539
+
540
+ if (nodeSymbol.escapedName === "prototype") {
541
+ // accessing to prototype
542
+ return putToCache(nodeSymbol, VisibilityType.External);
543
+ }
544
+
545
+ if (fullOptions.publicJSDocTag.length !== 0 || fullOptions.ignoreDecorated) {
546
+ for (const declaration of symbolDeclarations) {
547
+ let currentNode: ts.Node = declaration;
548
+ while (!ts.isSourceFile(currentNode)) {
549
+ if (
550
+ fullOptions.publicJSDocTag.length !== 0 &&
551
+ getNodeJSDocComment(currentNode).includes(`@${fullOptions.publicJSDocTag}`)
552
+ ) {
553
+ return putToCache(nodeSymbol, VisibilityType.External);
554
+ }
555
+
556
+ if (fullOptions.ignoreDecorated && hasDecorators(currentNode)) {
557
+ return putToCache(nodeSymbol, VisibilityType.External);
558
+ }
559
+
560
+ // TODO: mute enum renames
561
+ if (ts.isEnumDeclaration(currentNode)) {
562
+ return putToCache(nodeSymbol, VisibilityType.External);
563
+ }
564
+
565
+ currentNode = currentNode.parent;
566
+ }
567
+ }
568
+ }
569
+
570
+ if (isPrivateClassMember(nodeSymbol)) {
571
+ return putToCache(nodeSymbol, VisibilityType.Private);
572
+ }
573
+
574
+ if (exportsSymbolTree.isSymbolAccessibleFromExports(nodeSymbol)) {
575
+ return putToCache(nodeSymbol, VisibilityType.External);
576
+ }
577
+
578
+ for (const declaration of symbolDeclarations) {
579
+ if (!isNodeNamedDeclaration(declaration.parent) || declaration.parent.name === undefined) {
580
+ continue;
581
+ }
582
+
583
+ const parentSymbol = getNodeSymbol(declaration.parent.name);
584
+ if (parentSymbol === null) {
585
+ continue;
586
+ }
587
+
588
+ if (getSymbolVisibilityType(parentSymbol) === VisibilityType.External) {
589
+ return putToCache(nodeSymbol, VisibilityType.External);
590
+ }
591
+ }
592
+
593
+ return putToCache(nodeSymbol, VisibilityType.Internal);
594
+ }
595
+
596
+ function getShorthandObjectBindingElementSymbol(element: ts.BindingElement): ts.Symbol | null {
597
+ if (element.propertyName !== undefined) {
598
+ throw new Error(
599
+ `Cannot handle binding element with property name: ${element.getText()} in ${
600
+ element.getSourceFile().fileName
601
+ }`,
602
+ );
603
+ }
604
+
605
+ if (!ts.isIdentifier(element.name)) {
606
+ return null;
607
+ }
608
+
609
+ // if no property name is set (const { a } = foo)
610
+ // then node.propertyName is undefined and we need to find this property ourselves
611
+ // so let's use go-to-definition algorithm from TSServer
612
+ // see https://github.com/microsoft/TypeScript/blob/672b0e3e16ad18b422dbe0cec5a98fce49881b76/src/services/goToDefinition.ts#L58-L77
613
+ const type = typeChecker.getTypeAtLocation(element.parent as ts.Node);
614
+ if (type.isUnion()) {
615
+ return null;
616
+ }
617
+
618
+ return type.getProperty(ts.idText(element.name)) || null;
619
+ }
620
+
621
+ function isDeclarationFromExternals(declaration: ts.Declaration): boolean {
622
+ const sourceFile = declaration.getSourceFile();
623
+
624
+ // all declarations from declaration source files are external by default
625
+ return (
626
+ sourceFile.isDeclarationFile ||
627
+ program.isSourceFileDefaultLibrary(sourceFile) ||
628
+ /[\\/]node_modules[\\/]/.test(sourceFile.fileName)
629
+ );
630
+ }
631
+
632
+ function isConstructorParameterReference(node: ts.Node): node is ts.Identifier {
633
+ if (!ts.isIdentifier(node)) {
634
+ return false;
635
+ }
636
+
637
+ return isSymbolClassMember(typeChecker.getSymbolAtLocation(node));
638
+ }
639
+
640
+ return (sourceFile: ts.SourceFile) => transformNodeAndChildren(sourceFile, context);
641
+ };
642
+ }
@@ -0,0 +1,51 @@
1
+ export interface RenameOptions {
2
+ /**
3
+ * An array of entry source files which will used to detect exported and internal fields.
4
+ * Basically it should be entry point(s) of the library/project.
5
+ * @example ['./src/index.ts']
6
+ */
7
+ entrySourceFiles: string[];
8
+
9
+ /**
10
+ * Prefix of generated names for private fields
11
+ * @example '_private_' // default
12
+ * @example '$p$'
13
+ */
14
+ privatePrefix: string;
15
+
16
+ /**
17
+ * Prefix of generated names for internal fields
18
+ * @example '_internal_' // default
19
+ * @example '$i$'
20
+ */
21
+ internalPrefix: string;
22
+
23
+ /**
24
+ * Comment which will treat a class/interface/type/property/etc and all its children as "public".
25
+ * Set it to empty string to disable using JSDoc comment to detecting "visibility level".
26
+ * @example 'public' // default
27
+ * @example 'external'
28
+ * @example ''
29
+ */
30
+ publicJSDocTag: string;
31
+
32
+ /**
33
+ * Whether fields that were decorated should be renamed.
34
+ * A field is treated as "decorated" if itself or any its parent (on type level) has a decorator.
35
+ */
36
+ ignoreDecorated: boolean;
37
+ }
38
+
39
+ export const enum VisibilityType {
40
+ Internal = 0,
41
+ Private = 1,
42
+ External = 2,
43
+ }
44
+
45
+ export const defaultOptions: RenameOptions = {
46
+ entrySourceFiles: [],
47
+ privatePrefix: "$p$",
48
+ internalPrefix: "$i$",
49
+ publicJSDocTag: "public",
50
+ ignoreDecorated: false,
51
+ };