• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    /* @internal */
3    export function isInEtsFile(node: Node |undefined): boolean {
4        return node !== undefined && getSourceFileOfNode(node)?.scriptKind === ScriptKind.ETS;
5    }
6    /* @internal */
7    export function isInEtsFileWithOriginal(node: Node |undefined) {
8        while (node) {
9            node = node.original;
10            if (node !== undefined && getSourceFileOfNode(node)?.scriptKind === ScriptKind.ETS) {
11                return true;
12            }
13        }
14        return false;
15    }
16
17    /* @internal */
18    export function getReservedDecoratorsOfEtsFile(node: ClassDeclaration | StructDeclaration | FunctionDeclaration | MethodDeclaration | PropertyDeclaration, host: EmitHost): Decorator[] | undefined {
19        let reservedDecorators;
20        if (isInEtsFile(node)) {
21            reservedDecorators = ensureEtsDecorators(node, host);
22        }
23        return reservedDecorators;
24    }
25
26    /* @internal */
27    export function getReservedDecoratorsOfStructDeclaration(node: ClassDeclaration | StructDeclaration | FunctionDeclaration | MethodDeclaration | PropertyDeclaration, host: EmitHost): Decorator[] | undefined {
28        let reservedDecorators;
29        if (node.parent.kind === SyntaxKind.StructDeclaration) {
30            reservedDecorators = ensureEtsDecorators(node, host);
31        }
32        return reservedDecorators;
33    }
34
35    /* @internal */
36    export function ensureEtsDecorators(node: ClassDeclaration | StructDeclaration | FunctionDeclaration | MethodDeclaration | PropertyDeclaration, host: EmitHost): Decorator[] | undefined {
37        const allDecorators = getAllDecorators(node);
38        return getEffectiveDecorators(allDecorators, host);
39    }
40
41    export function concatenateDecoratorsAndModifiers(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined): readonly ModifierLike[] | undefined {
42        if (!decorators) return modifiers;
43        if (!modifiers) return decorators;
44        const decoratorsAndModifiers = concatenate<ModifierLike>(decorators, modifiers);
45        return decoratorsAndModifiers;
46    }
47
48    // Get the effective ETS Decorators for the node
49    /* @internal */
50    export function getEffectiveDecorators(decorators: readonly Decorator[] | NodeArray<Decorator> | undefined, host: EmitHost) {
51        const emitDecorators = host.getCompilerOptions().ets?.emitDecorators;
52        if (!emitDecorators) {
53            return undefined;
54        }
55        const reservedComponents: Decorator[] = [];
56        if (!decorators) {
57            return reservedComponents
58        }
59
60        for (let decorator of decorators) {
61            const expr = decorator.expression;
62            if (isIdentifier(expr)) {
63                for (const availableDecorator of emitDecorators) {
64                    if (availableDecorator.name === expr.escapedText.toString()) {
65                        reservedComponents.push(decorator);
66                        break;
67                    }
68                }
69            }
70            else if (isCallExpression(expr)) {
71                const childExpr = expr.expression;
72                if (isIdentifier(childExpr)) {
73                    for (const availableDecorator of emitDecorators) {
74                        if (availableDecorator.name === childExpr.escapedText.toString()) {
75                            if (!availableDecorator.emitParameters) {
76                                decorator = factory.updateDecorator(
77                                    decorator,
78                                    childExpr
79                                );
80                            }
81                            reservedComponents.push(decorator);
82                            break;
83                        }
84                    }
85                }
86            }
87        }
88
89        return reservedComponents;
90    }
91
92    /* @internal */
93    export function inEtsStylesContext(input: LateVisibilityPaintedStatement | MethodDeclaration, host: EmitHost) {
94        if (!host.getCompilerOptions().ets?.styles.component || getSourceFileOfNode(input).scriptKind !== ScriptKind.ETS) {
95            return false;
96        }
97        const decorators: readonly Decorator[] = getAllDecorators(input);
98
99        if (decorators.length == 0) {
100            return false;
101        }
102        for (const decorator of decorators) {
103            if (isIdentifier(decorator.expression) && decorator.expression.escapedText.toString() === "Styles") {
104                return true;
105            }
106        }
107        return false;
108    }
109
110    export function isEtsFunctionDecorators(name: string | undefined, options: CompilerOptions): boolean {
111        return (name === options.ets?.render?.decorator || name === options.ets?.styles?.decorator ||
112            (options.ets?.extend?.decorator?.includes(name as string) ?? false));
113    }
114
115    export function isOhpm(packageManagerType: string | undefined): boolean {
116        return packageManagerType === "ohpm";
117    }
118
119    export const ohModulesPathPart: string = "/oh_modules/";
120    export function isOHModules(modulePath: string): boolean {
121        return modulePath.indexOf(ohModulesPathPart) >= 0;
122    }
123
124    export function isOhpmAndOhModules(packageManagerType: string | undefined, modulePath: string): boolean {
125        return isOhpm(packageManagerType) && isOHModules(modulePath);
126    }
127
128    export function getModulePathPartByPMType(packageManagerType: string | undefined): string {
129        return isOhpm(packageManagerType) ? ohModulesPathPart : nodeModulesPathPart
130    }
131
132    export function getModuleByPMType(packageManagerType: string | undefined): string {
133        if (isOhpm(packageManagerType)) {
134            return "oh_modules";
135        }
136        return "node_modules";
137    }
138
139    export function getPackageJsonByPMType(packageManagerType: string | undefined): string {
140        if (isOhpm(packageManagerType)) {
141            return "oh-package.json5";
142        }
143        return "package.json";
144    }
145
146    export function isOHModulesDirectory(dirPath: Path) {
147        return endsWith(dirPath, "/oh_modules");
148    }
149
150    export function isTargetModulesDerectory(dirPath: Path): boolean {
151        return isNodeModulesDirectory(dirPath) || isOHModulesDirectory(dirPath);
152    }
153    export function pathContainsOHModules(path: string): boolean {
154        return stringContains(path, ohModulesPathPart);
155    }
156
157    export function choosePathContainsModules(packageManagerType: string | undefined, fileName: string): boolean {
158        return isOhpm(packageManagerType) ? pathContainsOHModules(fileName) : pathContainsNodeModules(fileName);
159    }
160
161    /* @internal */
162    export function isOHModulesAtTypesDirectory(dirPath: Path) {
163        return endsWith(dirPath, "/oh_modules/@types");
164    }
165
166    /* @internal */
167    export function isOHModulesReference(fileName: string): boolean {
168        return startsWith(fileName, "oh_modules/") || pathContainsOHModules(fileName);
169    }
170
171    /* @internal */
172    export function isArkTsDecorator(node: Node, compilerOptions?: CompilerOptions): boolean {
173        if (compilerOptions) {
174            return hasEtsExtendDecoratorNames(getAllDecorators(node), compilerOptions) ||
175            hasEtsStylesDecoratorNames(getAllDecorators(node), compilerOptions) ||
176            hasEtsBuilderDecoratorNames(getAllDecorators(node), compilerOptions) ||
177            hasEtsConcurrentDecoratorNames(getAllDecorators(node), compilerOptions);
178        }
179        return false;
180    }
181
182    /* @internal */
183    export function hasEtsExtendDecoratorNames(decorators: NodeArray<Decorator> | readonly Decorator[] | undefined, options: CompilerOptions): boolean {
184        const names: string[] = [];
185        if (!decorators || !decorators.length) {
186            return false;
187        }
188        decorators.forEach(decorator => {
189            const nameExpr = decorator.expression;
190            if (isCallExpression(nameExpr) && isIdentifier(nameExpr.expression) &&
191                options.ets?.extend.decorator?.includes(nameExpr.expression.escapedText.toString())) {
192                    names.push(nameExpr.expression.escapedText.toString());
193            }
194        });
195        return names.length !== 0;
196    }
197
198    /* @internal */
199    export function hasEtsStylesDecoratorNames(decorators: NodeArray<Decorator> | readonly Decorator[] | undefined, options: CompilerOptions): boolean {
200        const names: string[] = [];
201        if (!decorators || !decorators.length) {
202            return false;
203        }
204        decorators.forEach(decorator => {
205            const nameExpr = decorator.expression;
206            if (isIdentifier(nameExpr) && nameExpr.escapedText.toString() === options.ets?.styles?.decorator) {
207                names.push(nameExpr.escapedText.toString());
208            }
209        });
210        return names.length !== 0;
211    }
212
213    /* @internal */
214    export function hasEtsBuildDecoratorNames(decorators: NodeArray<Decorator> | readonly Decorator[] | undefined, options: CompilerOptions): boolean {
215        const names: string[] = [];
216        if (!decorators || !decorators.length) {
217            return false;
218        }
219        decorators.forEach(decorator => {
220            const nameExpr = decorator.expression;
221            if (isIdentifier(nameExpr) && options.ets?.render?.method.indexOf(nameExpr.escapedText.toString()) !== -1) {
222                names.push(nameExpr.escapedText.toString());
223            }
224        });
225        return names.length !== 0;
226    }
227
228    /* @internal */
229    export function hasEtsBuilderDecoratorNames(decorators: NodeArray<Decorator> | readonly Decorator[] | undefined, options: CompilerOptions): boolean {
230        const names: string[] = [];
231        if (!decorators || !decorators.length) {
232        return false;
233        }
234        decorators.forEach(decorator => {
235            const nameExpr = decorator.expression;
236            if (isIdentifier(nameExpr) && nameExpr.escapedText.toString() === options.ets?.render?.decorator) {
237                names.push(nameExpr.escapedText.toString());
238            }
239        });
240        return names.length !== 0;
241    }
242
243    /* @internal */
244    export function hasEtsConcurrentDecoratorNames(decorators: NodeArray<Decorator> | readonly Decorator[] | undefined, options: CompilerOptions): boolean {
245        const names: string[] = [];
246        if (!decorators || !decorators.length) {
247            return false;
248        }
249        decorators.forEach(decorator => {
250            const nameExpr = decorator.expression;
251            if (isIdentifier(nameExpr) && nameExpr.escapedText.toString() === options.ets?.concurrent?.decorator) {
252                names.push(nameExpr.escapedText.toString());
253            }
254        });
255        return names.length !== 0;
256    }
257
258    /* @internal */
259    export function isTokenInsideBuilder(decorators: NodeArray<Decorator> | readonly Decorator[] | undefined, compilerOptions: CompilerOptions): boolean {
260        const renderDecorator = compilerOptions.ets?.render?.decorator ?? "Builder";
261
262        if (!decorators) {
263            return false;
264        }
265
266        for (const decorator of decorators) {
267            if (decorator.expression.kind === SyntaxKind.Identifier && (<Identifier>(decorator.expression)).escapedText === renderDecorator) {
268                return true;
269            }
270        }
271        return false;
272    }
273
274    /* @internal */
275    export function getEtsComponentExpressionInnerCallExpressionNode(node: Node | undefined): EtsComponentExpression | undefined {
276        while (node && node.kind !== SyntaxKind.EtsComponentExpression) {
277            if (node.kind === SyntaxKind.CallExpression) {
278                node = (<CallExpression>node).expression;
279            }
280            else if (node.kind === SyntaxKind.PropertyAccessExpression) {
281                node = (<PropertyAccessExpression>node).expression;
282            }
283            else {
284                node = undefined;
285            }
286        }
287        return <EtsComponentExpression>node;
288    }
289
290    /* @internal */
291    export function getRootEtsComponentInnerCallExpressionNode(node: Node | undefined): EtsComponentExpression | undefined {
292        if (node && isEtsComponentExpression(node)) {
293            return node;
294        }
295
296        while (node) {
297            const ancestor = <CallExpression>getAncestor(isCallExpression(node) ? node.parent : node, SyntaxKind.CallExpression);
298            const target = getRootEtsComponent(ancestor);
299            if (target && isInStateStylesObject(node)) {
300                return target;
301            }
302            node = ancestor ?? node.parent;
303        }
304
305        return undefined;
306    }
307
308    /* @internal */
309    export function getEtsComponentExpressionInnerExpressionStatementNode(node: Node | undefined): CallExpression | EtsComponentExpression | PropertyAccessExpression | undefined {
310        while (node && !isIdentifier(node)) {
311            const parent = node;
312            const currentNode = (node as ExpressionStatement | CallExpression | PropertyAccessExpression | EtsComponentExpression).expression;
313            if (currentNode && isIdentifier(currentNode)) {
314                node = parent;
315                break;
316            }
317            else {
318                node = currentNode;
319            }
320        }
321        if (!node) {
322            return undefined;
323        }
324        if (isCallExpression(node) || isEtsComponentExpression(node) || isPropertyAccessExpression(node)) {
325            return node;
326        }
327        return undefined;
328    }
329
330    /* @internal */
331    function isInStateStylesObject(node: Node | undefined): boolean {
332        const ancestor = <ObjectLiteralExpression>getAncestor(node, SyntaxKind.ObjectLiteralExpression);
333        return ancestor !== undefined && ancestor.parent !== undefined && isPropertyAssignment(ancestor.parent);
334    }
335
336    /* @internal */
337    export function getEtsExtendDecoratorsComponentNames(decorators: NodeArray<Decorator> | readonly Decorator[] | undefined, compilerOptions: CompilerOptions): __String[] {
338        const extendComponents: __String[] = [];
339        const extendDecorator = compilerOptions.ets?.extend?.decorator ?? "Extend";
340        decorators?.forEach((decorator) => {
341            if (decorator.expression.kind === SyntaxKind.CallExpression) {
342                const identifier = (<CallExpression>decorator.expression).expression;
343                const args = (<CallExpression>decorator.expression).arguments;
344                if (identifier.kind === SyntaxKind.Identifier && extendDecorator?.includes((<Identifier>identifier).escapedText.toString()) && args.length) {
345                    // only read @Extend(...args) first argument
346                    if (args[0].kind === SyntaxKind.Identifier) {
347                        extendComponents.push((<Identifier>args[0]).escapedText);
348                    }
349                }
350            }
351        });
352        return extendComponents;
353    }
354
355    /* @internal */
356    export function getEtsStylesDecoratorComponentNames(decorators: NodeArray<Decorator> | readonly Decorator[] | undefined, compilerOptions: CompilerOptions): __String[] {
357        const stylesComponents: __String[] = [];
358        const stylesDecorator = compilerOptions.ets?.styles?.decorator ?? "Styles";
359        decorators?.forEach(decorator => {
360            if (decorator.kind === SyntaxKind.Decorator && decorator.expression.kind === SyntaxKind.Identifier) {
361                const identifier = <Identifier>decorator.expression;
362                if (identifier.kind === SyntaxKind.Identifier && identifier.escapedText === stylesDecorator) {
363                    stylesComponents.push(identifier.escapedText);
364                }
365            }
366        });
367        return stylesComponents;
368    }
369
370    /* @internal */
371    export function filterEtsExtendDecoratorComponentNamesByOptions(decoratorComponentNames: __String[], compilerOptions: CompilerOptions): __String[] {
372        if (!decoratorComponentNames.length) {
373            return [];
374        }
375        const filtered: __String[] = [];
376        compilerOptions.ets?.extend.components.forEach(({ name }) => {
377            if (name === last(decoratorComponentNames)) {
378                filtered.push(name);
379            }
380        });
381        return filtered;
382    }
383
384    export function getTypeExportImportAndConstEnumTransformer(context: TransformationContext): (node: SourceFile) => SourceFile {
385        return transformTypeExportImportAndConstEnumInTypeScript(context);
386    }
387
388    /**
389     * Add 'type' flag to import/export when import/export an type member.
390     * Replace const enum with number and string literal.
391     */
392    export function transformTypeExportImportAndConstEnumInTypeScript(context: TransformationContext): (node: SourceFile) => SourceFile {
393        const resolver = context.getEmitResolver();
394        interface ImportInfo {
395            name: Identifier | undefined,
396            namespaceImport: NamespaceImport | undefined,
397            namedImports: ImportSpecifier[]
398        };
399        interface ExportInfo {
400            namedExports: ExportSpecifier[]
401        };
402
403        // recore type import/export info to create new import/export type statement
404        let currentTypeImportInfo: ImportInfo;
405        let currentTypeExportInfo: ExportInfo;
406
407        return transformSourceFile;
408
409        function transformSourceFile(node: SourceFile): SourceFile {
410            if (node.isDeclarationFile) {
411                return node;
412            }
413            const visited = factory.updateSourceFile(
414                node,
415                visitLexicalEnvironment(node.statements, visitImportExportAndConstEnumMember, context));
416            return visited;
417        }
418
419        function visitImportExportAndConstEnumMember(node: Node): VisitResult<Node> {
420            switch (node.kind) {
421                case SyntaxKind.ImportDeclaration:
422                    return visitImportDeclaration(<ImportDeclaration>node);
423                case SyntaxKind.ImportEqualsDeclaration:
424                    return visitImportEqualsDeclaration(<ImportEqualsDeclaration>node);
425                case SyntaxKind.ExportDeclaration:
426                    return visitExportDeclaration(<ExportDeclaration>node);
427                case SyntaxKind.PropertyAccessExpression:
428                case SyntaxKind.ElementAccessExpression:
429                    return visitConstEnum(<PropertyAccessExpression | ElementAccessExpression>node);
430                case SyntaxKind.EnumMember:
431                    return visitEnumMember(<EnumMember>node);
432                default:
433                    return visitEachChild(node, visitImportExportAndConstEnumMember, context);
434            }
435        }
436
437        /**
438         * Transform:
439         *
440         * import a, {b, c} from ...
441         *
442         * To:
443         *
444         * import {b} from ...
445         * import type a from ...
446         * import type {c} from ...
447         *
448         * when 'a' and 'c' are type.
449         */
450        function visitImportDeclaration(node: ImportDeclaration): VisitResult<Statement> {
451            // return if the import already has 'type'
452            if (!node.importClause || node.importClause.isTypeOnly) {
453                return node;
454            }
455            resetcurrentTypeImportInfo();
456            const res: Statement[] = [];
457            const importClause = visitNode(node.importClause, visitImportClause, isImportClause);
458            if (importClause) {
459                res.push(factory.updateImportDeclaration(node, /*modifiers*/ undefined,
460                    importClause, node.moduleSpecifier, /*assertClause*/ undefined));
461            }
462            // create new import statement with 'type'
463            const typeImportClauses = createTypeImportClause();
464            for (const typeImportClause of typeImportClauses) {
465                res.push(factory.createImportDeclaration(/*modifiers*/ undefined,
466                    typeImportClause, node.moduleSpecifier));
467            }
468            return res.length > 0 ? res : undefined;
469        }
470
471        function visitImportClause(node: ImportClause): VisitResult<ImportClause> {
472            if (node.isTypeOnly) {
473                return node;
474            }
475            let name: Identifier | undefined;
476            if (resolver.isReferencedAliasDeclaration(node)) {
477                name = node.name;
478            }
479            // consider it is a type if the symbol has referenced.
480            else if (resolver.isReferenced(node)) {
481                addTypeImportClauseName(node);
482            }
483            const namedBindings = visitNode(node.namedBindings, visitNamedImportBindings, isNamedImportBindings);
484            return (name || namedBindings) ?
485                factory.updateImportClause(node, /*isTypeOnly*/ false, name, namedBindings) :
486                undefined;
487        }
488
489        function visitNamedImportBindings(node: NamedImportBindings): VisitResult<NamedImportBindings> {
490            if (node.kind === SyntaxKind.NamespaceImport) {
491                if (resolver.isReferencedAliasDeclaration(node)) {
492                    return node;
493                }
494                if (resolver.isReferenced(node)) {
495                    addTypeNamespaceImport(node);
496                }
497                return undefined;
498            }
499            else {
500                const elements = visitNodes(node.elements, visitImportSpecifier, isImportSpecifier);
501                return some(elements) ? factory.updateNamedImports(node, elements) : undefined;
502            }
503        }
504
505        function visitImportSpecifier(node: ImportSpecifier): VisitResult<ImportSpecifier> {
506            if (node.isTypeOnly) {
507                return node;
508            }
509            if (resolver.isReferencedAliasDeclaration(node)) {
510                return node;
511            }
512            if (resolver.isReferenced(node)) {
513                addTypeImportSpecifier(node);
514            }
515            return undefined;
516        }
517
518        function addTypeImportClauseName(node: ImportClause): void {
519            currentTypeImportInfo.name = node.name;
520        }
521
522        function addTypeNamespaceImport(node: NamespaceImport): void {
523            currentTypeImportInfo.namespaceImport = node;
524        }
525
526        function addTypeImportSpecifier(node: ImportSpecifier): void {
527            currentTypeImportInfo.namedImports.push(node);
528        }
529
530        /**
531         * Create new import type statement, like:
532         * import type {a} from ...
533         */
534        function createTypeImportClause(): ImportClause[] {
535            const name: Identifier | undefined = currentTypeImportInfo.name;
536            let namedBindings: NamedImportBindings | undefined;
537            if (currentTypeImportInfo.namespaceImport) {
538                namedBindings = currentTypeImportInfo.namespaceImport;
539            }
540            else if (currentTypeImportInfo.namedImports.length > 0) {
541                namedBindings = factory.createNamedImports(currentTypeImportInfo.namedImports);
542            }
543            const typeImportClauses: ImportClause[] = [];
544            if (name !== undefined) {
545                typeImportClauses.push(factory.createImportClause(/*isTypeOnly*/ true, name, /*namedBindings*/ undefined));
546            }
547            if (namedBindings !== undefined) {
548                typeImportClauses.push(factory.createImportClause(/*isTypeOnly*/ true, /*name*/ undefined, namedBindings));
549            }
550            resetcurrentTypeImportInfo();
551            return typeImportClauses;
552        }
553
554        /**
555         * Transform:
556         *
557         * import a = require(...)
558         *
559         * To:
560         *
561         * import type a = require(...)
562         *
563         * when 'a' is type.
564         */
565        function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult<Statement> {
566            // return if the import already has 'type'
567            if (node.isTypeOnly) {
568                return node;
569            }
570
571            if (isExternalModuleImportEqualsDeclaration(node)) {
572                const isReferenced = resolver.isReferencedAliasDeclaration(node);
573                if (isReferenced) {
574                    return node;
575                }
576                if (resolver.isReferenced(node)) {
577                    return factory.updateImportEqualsDeclaration(node, node.modifiers,
578                        /*isTypeOnly*/ true, node.name, node.moduleReference);
579                }
580
581                return undefined;
582            }
583
584            return node;
585        }
586
587        /**
588         * Transform:
589         *
590         * export {a}
591         *
592         * To:
593         *
594         * export type {a}
595         *
596         * when 'a' is type.
597         */
598        function visitExportDeclaration(node: ExportDeclaration): VisitResult<Statement> {
599            // return if the export already has 'type'or export *
600            if (node.isTypeOnly || !node.exportClause || isNamespaceExport(node.exportClause)) {
601                return node;
602            }
603
604            resetcurrentTypeExportInfo();
605            const res: Statement[] = [];
606
607            const exportClause = visitNode(node.exportClause, visitNamedExports, isNamedExportBindings);
608            if (exportClause) {
609                res.push(factory.updateExportDeclaration(node, /*modifiers*/ undefined,
610                    node.isTypeOnly, exportClause, node.moduleSpecifier, /*assertClause*/ undefined));
611            }
612            const typeExportClause = createTypeExportClause();
613            if (typeExportClause) {
614                res.push(factory.createExportDeclaration(/*modifiers*/ undefined,
615                    /*isTypeOnly*/ true, typeExportClause, node.moduleSpecifier));
616            }
617
618            return res.length > 0 ? res : undefined;
619        }
620
621        function visitNamedExports(node: NamedExports): VisitResult<NamedExports> {
622            const elements = visitNodes(node.elements, visitExportSpecifier, isExportSpecifier);
623            return some(elements) ? factory.updateNamedExports(node, elements) : undefined;
624        }
625
626        function visitExportSpecifier(node: ExportSpecifier): VisitResult<ExportSpecifier> {
627            if (node.isTypeOnly) {
628                return node;
629            }
630            if (resolver.isValueAliasDeclaration(node)) {
631                return node;
632            }
633            // consider all rest member are type.
634            addTypeExportSpecifier(node);
635            return undefined;
636        }
637
638        function addTypeExportSpecifier(node: ExportSpecifier): void {
639            currentTypeExportInfo.namedExports.push(node);
640        }
641
642        /**
643         * Create new export type statement, like:
644         * export type {a}
645         */
646        function createTypeExportClause(): NamedExports | undefined {
647            let namedBindings: NamedExports | undefined;
648            if (currentTypeExportInfo.namedExports.length > 0) {
649                namedBindings = factory.createNamedExports(currentTypeExportInfo.namedExports);
650            }
651            resetcurrentTypeExportInfo();
652            return namedBindings;
653        }
654
655        function visitConstEnum(node: PropertyAccessExpression | ElementAccessExpression): LeftHandSideExpression {
656            const constantValue = resolver.getConstantValue(node);
657            if (constantValue !== undefined) {
658                const substitute = typeof constantValue === "string" ?
659                    factory.createStringLiteral(constantValue) :
660                    factory.createNumericLiteral(constantValue);
661                return substitute;
662            }
663
664            return visitEachChild(node, visitImportExportAndConstEnumMember, context);
665        }
666
667        /**
668         * If the enum member is a const value, replace it.
669         */
670        function visitEnumMember(node: EnumMember): VisitResult<EnumMember> {
671            const value = resolver.getConstantValue(node);
672            if (value !== undefined) {
673                const substitute = typeof value === "string" ?
674                    factory.createStringLiteral(value) :
675                    factory.createNumericLiteral(value);
676                return factory.updateEnumMember(node, node.name, substitute);
677            }
678            return visitEachChild(node, visitImportExportAndConstEnumMember, context);
679        }
680
681        function resetcurrentTypeImportInfo(): void {
682            currentTypeImportInfo = { name: undefined, namespaceImport: undefined, namedImports:[] };
683        }
684
685        function resetcurrentTypeExportInfo(): void {
686            currentTypeExportInfo = { namedExports:[] };
687        }
688    }
689
690    export function hasTsNoCheckOrTsIgnoreFlag(node: SourceFile): boolean {
691        // check @ts-nocheck flag
692        if (!!node.checkJsDirective && node.checkJsDirective.enabled === false) {
693            return true;
694        }
695        // check @ts-ignore flag
696        if (node.commentDirectives !== undefined) {
697            for (const commentDirective of node.commentDirectives) {
698                if (commentDirective.type === CommentDirectiveType.Ignore) {
699                    return true;
700                }
701            }
702        }
703        return false;
704    }
705
706    export function createObfTextSingleLineWriter(): EmitTextWriter {
707        const space: string = " ";
708        let output: string;
709        let lineStart: boolean;
710        let linePos: number;
711
712        function updateLineCountAndPosFor(s: string) {
713            const lineStartsOfS = computeLineStarts(s);
714            if (lineStartsOfS.length > 1) {
715                linePos = output.length - s.length + last(lineStartsOfS);
716                lineStart = (linePos - output.length) === 0;
717            }
718            else {
719                lineStart = false;
720            }
721        }
722
723        function writeText(s: string) {
724            if (s && s.length) {
725                if (lineStart) {
726                    lineStart = false;
727                }
728                output += s;
729                updateLineCountAndPosFor(s);
730            }
731        }
732
733        function write(s: string) {
734            writeText(s);
735        }
736
737        function reset(): void {
738            output = "";
739            lineStart = true;
740            linePos = 0;
741        }
742
743        function rawWrite(s: string) {
744            if (s !== undefined) {
745                output += s;
746                updateLineCountAndPosFor(s);
747            }
748        }
749
750        function writeLiteral(s: string) {
751            if (s && s.length) {
752                write(s);
753            }
754        }
755
756        function writeLine(force?: boolean) {
757            if (!lineStart || force) {
758                output += space;
759                linePos = output.length;
760            }
761        }
762
763        function getTextPosWithWriteLine() {
764            return lineStart ? output.length : (output.length + space.length);
765        }
766
767        reset();
768
769        return {
770            write,
771            rawWrite,
772            writeLiteral,
773            writeLine,
774            increaseIndent: noop,
775            decreaseIndent: noop,
776            getIndent: () => 0,
777            getTextPos: () => output.length,
778            getLine: () => 0,
779            getColumn: () => lineStart ? 0 : output.length - linePos,
780            getText: () => output,
781            isAtStartOfLine: () => lineStart,
782            hasTrailingComment: () => false,
783            hasTrailingWhitespace: () => !!output.length && isWhiteSpaceLike(output.charCodeAt(output.length - 1)),
784            clear: reset,
785            reportInaccessibleThisError: noop,
786            reportPrivateInBaseOfClassExpression: noop,
787            reportInaccessibleUniqueSymbolError: noop,
788            trackSymbol: () => false,
789            writeKeyword: write,
790            writeOperator: write,
791            writeParameter: write,
792            writeProperty: write,
793            writePunctuation: write,
794            writeSpace: write,
795            writeStringLiteral: write,
796            writeSymbol: (s, _) => write(s),
797            writeTrailingSemicolon: write,
798            writeComment: noop,
799            getTextPosWithWriteLine
800        };
801    }
802}