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