• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import {
2    __String,
3    Annotation,
4    AnnotationDeclaration,
5    AnnotationPropertyDeclaration,
6    CallExpression,
7    ClassDeclaration,
8    CommentDirectiveType,
9    CompilerOptions,
10    computeLineStarts,
11    concatenate,
12    Debug,
13    Decorator,
14    Diagnostic,
15    ElementAccessExpression,
16    EmitHost,
17    EmitTextWriter,
18    endsWith,
19    EnumMember,
20    EtsComponentExpression,
21    ExportDeclaration,
22    ExportSpecifier,
23    Expression,
24    ExpressionStatement,
25    factory,
26    flattenDiagnosticMessageText,
27    FunctionDeclaration,
28    getAllDecorators,
29    getAncestor,
30    getIllegalDecorators,
31    getLineAndCharacterOfPosition,
32    getRootEtsComponent,
33    getSourceFileOfNode,
34    Identifier,
35    ImportClause,
36    ImportDeclaration,
37    ImportEqualsDeclaration,
38    ImportSpecifier,
39    isCallExpression,
40    isEtsComponentExpression,
41    isExportSpecifier,
42    isExternalModuleImportEqualsDeclaration,
43    isFunctionDeclaration,
44    isIdentifier,
45    isImportClause,
46    isImportDeclaration,
47    isImportSpecifier,
48    isNamedExportBindings,
49    isNamedImportBindings,
50    isNamespaceImport,
51    isNamespaceExport,
52    isNodeModulesDirectory,
53    isPropertyAccessExpression,
54    isPropertyAssignment,
55    isStringLiteral,
56    isStructDeclaration,
57    isTypeAliasDeclaration,
58    isWhiteSpaceLike,
59    last,
60    LateVisibilityPaintedStatement,
61    LeftHandSideExpression,
62    LineAndCharacter,
63    MethodDeclaration,
64    Modifier,
65    ModifierLike,
66    Mutable,
67    NamedExports,
68    NamedImports,
69    NamedImportBindings,
70    NamespaceImport,
71    Node,
72    NodeArray,
73    NodeFactory,
74    NodeFlags,
75    nodeModulesPathPart,
76    noop,
77    ObjectLiteralExpression,
78    Path,
79    pathContainsNodeModules,
80    PropertyAccessExpression,
81    PropertyAssignment,
82    PropertyDeclaration,
83    resolvePath,
84    setTextRangePosEnd,
85    ScriptKind,
86    some,
87    SourceFile,
88    sys,
89    startsWith,
90    Statement,
91    stringContains,
92    StringLiteral,
93    StructDeclaration,
94    SyntaxKind,
95    TextRange,
96    TransformationContext,
97    TransformerFactory,
98    tryGetTextOfPropertyName,
99    visitEachChild,
100    visitLexicalEnvironment,
101    visitNode,
102    visitNodes,
103    VisitResult,
104    unescapeLeadingUnderscores,
105    normalizePath,
106} from "./_namespaces/ts";
107
108/** @internal */
109// Required for distinguishing annotations and decorators in other code analysis tools
110export const annotationMagicNamePrefix = "__$$ETS_ANNOTATION$$__";
111const maxFlowDepthDefaultValue: number = 2000;
112
113/** @internal */
114export function isInEtsFile(node: Node |undefined): boolean {
115    return node !== undefined && getSourceFileOfNode(node)?.scriptKind === ScriptKind.ETS;
116}
117/** @internal */
118export function isInEtsFileWithOriginal(node: Node |undefined) {
119    while (node) {
120        node = node.original;
121        if (node !== undefined && getSourceFileOfNode(node)?.scriptKind === ScriptKind.ETS) {
122            return true;
123        }
124    }
125    return false;
126}
127
128/** @internal */
129export function getReservedDecoratorsOfEtsFile(node: ClassDeclaration | StructDeclaration | FunctionDeclaration | MethodDeclaration | PropertyDeclaration, host: EmitHost): Decorator[] | undefined {
130    let reservedDecorators;
131    if (isInEtsFile(node)) {
132        reservedDecorators = ensureEtsDecorators(node, host);
133    }
134    return reservedDecorators;
135}
136
137/** @internal */
138export function getReservedDecoratorsOfStructDeclaration(node: ClassDeclaration | StructDeclaration | FunctionDeclaration | MethodDeclaration | PropertyDeclaration, host: EmitHost): Decorator[] | undefined {
139    let reservedDecorators;
140    if (node.parent.kind === SyntaxKind.StructDeclaration) {
141        reservedDecorators = ensureEtsDecorators(node, host);
142    }
143    return reservedDecorators;
144}
145
146/** @internal */
147export function ensureEtsDecorators(node: ClassDeclaration | StructDeclaration | FunctionDeclaration | MethodDeclaration | PropertyDeclaration, host: EmitHost): Decorator[] | undefined {
148    const allDecorators = getAllDecorators(node);
149    return getEffectiveDecorators(allDecorators, host);
150}
151
152export function concatenateDecoratorsAndModifiers(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined): readonly ModifierLike[] | undefined {
153    if (!decorators) return modifiers;
154    if (!modifiers) return decorators;
155    const decoratorsAndModifiers = concatenate<ModifierLike>(decorators, modifiers);
156    return decoratorsAndModifiers;
157}
158
159/**
160 * @internal
161 * Get the effective ETS Decorators for the node
162 *  */
163export function getEffectiveDecorators(decorators: readonly Decorator[] | NodeArray<Decorator> | undefined, host: EmitHost) {
164    const emitDecorators = host.getCompilerOptions().ets?.emitDecorators;
165    if (!emitDecorators) {
166        return undefined;
167    }
168    const reservedComponents: Decorator[] = [];
169    if (!decorators) {
170        return reservedComponents
171    }
172
173    for (let decorator of decorators) {
174        const expr = decorator.expression;
175        if (isIdentifier(expr)) {
176            for (const availableDecorator of emitDecorators) {
177                if (availableDecorator.name === expr.escapedText.toString()) {
178                    reservedComponents.push(decorator);
179                    break;
180                }
181            }
182        }
183        else if (isCallExpression(expr)) {
184            const childExpr = expr.expression;
185            if (isIdentifier(childExpr)) {
186                for (const availableDecorator of emitDecorators) {
187                    if (availableDecorator.name === childExpr.escapedText.toString()) {
188                        if (!availableDecorator.emitParameters) {
189                            decorator = factory.updateDecorator(
190                                decorator,
191                                childExpr
192                            );
193                        }
194                        reservedComponents.push(decorator);
195                        break;
196                    }
197                }
198            }
199        }
200    }
201
202    return reservedComponents;
203}
204
205/** @internal */
206export function inEtsStylesContext(input: LateVisibilityPaintedStatement | MethodDeclaration, host: EmitHost) {
207    if (!host.getCompilerOptions().ets?.styles.component || getSourceFileOfNode(input).scriptKind !== ScriptKind.ETS) {
208        return false;
209    }
210    const decorators: readonly Decorator[] = getAllDecorators(input);
211
212    if (decorators.length == 0) {
213        return false;
214    }
215    for (const decorator of decorators) {
216        if (isIdentifier(decorator.expression) && decorator.expression.escapedText.toString() === "Styles") {
217            return true;
218        }
219    }
220    return false;
221}
222
223export function isEtsFunctionDecorators(name: string | undefined, options: CompilerOptions): boolean {
224    const renderDecorators: string[] | undefined = options.ets?.render?.decorator;
225    return ((renderDecorators?.length && name && renderDecorators.includes(name)) ||
226        name === options.ets?.styles?.decorator || (options.ets?.extend?.decorator?.includes(name as string) ?? false));
227}
228
229export function isOhpm(packageManagerType: string | undefined): boolean {
230    return packageManagerType === "ohpm";
231}
232
233export const ohModulesPathPart: string = "/oh_modules/";
234export function isOHModules(modulePath: string): boolean {
235    return modulePath.indexOf(ohModulesPathPart) >= 0;
236}
237
238export function isOhpmAndOhModules(packageManagerType: string | undefined, modulePath: string): boolean {
239    return isOhpm(packageManagerType) && isOHModules(modulePath);
240}
241
242export function getModulePathPartByPMType(packageManagerType: string | undefined): string {
243    return isOhpm(packageManagerType) ? ohModulesPathPart : nodeModulesPathPart
244}
245
246export function getModuleByPMType(packageManagerType: string | undefined): string {
247    if (isOhpm(packageManagerType)) {
248        return "oh_modules";
249    }
250    return "node_modules";
251}
252
253export function getPackageJsonByPMType(packageManagerType: string | undefined): string {
254    if (isOhpm(packageManagerType)) {
255        return "oh-package.json5";
256    }
257    return "package.json";
258}
259
260export function isOHModulesDirectory(dirPath: Path) {
261    return endsWith(dirPath, "/oh_modules");
262}
263
264export function isTargetModulesDerectory(dirPath: Path): boolean {
265    return isNodeModulesDirectory(dirPath) || isOHModulesDirectory(dirPath);
266}
267export function pathContainsOHModules(path: string): boolean {
268    return stringContains(path, ohModulesPathPart);
269}
270
271export function choosePathContainsModules(packageManagerType: string | undefined, fileName: string): boolean {
272    return isOhpm(packageManagerType) ? pathContainsOHModules(fileName) : pathContainsNodeModules(fileName);
273}
274
275/** @internal */
276export function isOHModulesAtTypesDirectory(dirPath: Path) {
277    return endsWith(dirPath, "/oh_modules/@types");
278}
279
280/** @internal */
281export function isOHModulesReference(fileName: string): boolean {
282    return startsWith(fileName, "oh_modules/") || pathContainsOHModules(fileName);
283}
284
285/** @internal */
286export function isArkTsDecorator(node: Node, compilerOptions?: CompilerOptions): boolean {
287    if (compilerOptions) {
288        return hasEtsExtendDecoratorNames(getAllDecorators(node), compilerOptions) ||
289        hasEtsStylesDecoratorNames(getAllDecorators(node), compilerOptions) ||
290        hasEtsBuilderDecoratorNames(getAllDecorators(node), compilerOptions) ||
291        hasEtsConcurrentDecoratorNames(getAllDecorators(node), compilerOptions);
292    }
293    return false;
294}
295
296/** @internal */
297export function hasEtsExtendDecoratorNames(decorators: NodeArray<Decorator> | readonly Decorator[] | undefined, options: CompilerOptions): boolean {
298    const names: string[] = [];
299    if (!decorators || !decorators.length) {
300        return false;
301    }
302    decorators.forEach(decorator => {
303        const nameExpr = decorator.expression;
304        if (isCallExpression(nameExpr) && isIdentifier(nameExpr.expression) &&
305            options.ets?.extend.decorator?.includes(nameExpr.expression.escapedText.toString())) {
306                names.push(nameExpr.expression.escapedText.toString());
307        }
308    });
309    return names.length !== 0;
310}
311
312/** @internal */
313export function hasEtsStylesDecoratorNames(decorators: NodeArray<Decorator> | readonly Decorator[] | undefined, options: CompilerOptions): boolean {
314    const names: string[] = [];
315    if (!decorators || !decorators.length) {
316        return false;
317    }
318    decorators.forEach(decorator => {
319        const nameExpr = decorator.expression;
320        if (isIdentifier(nameExpr) && nameExpr.escapedText.toString() === options.ets?.styles?.decorator) {
321            names.push(nameExpr.escapedText.toString());
322        }
323    });
324    return names.length !== 0;
325}
326
327/** @internal */
328export function hasEtsBuildDecoratorNames(decorators: NodeArray<Decorator> | readonly Decorator[] | undefined, options: CompilerOptions): boolean {
329    const names: string[] = [];
330    if (!decorators || !decorators.length) {
331        return false;
332    }
333    decorators.forEach(decorator => {
334        const nameExpr = decorator.expression;
335        if (isIdentifier(nameExpr) && options.ets?.render?.method.indexOf(nameExpr.escapedText.toString()) !== -1) {
336            names.push(nameExpr.escapedText.toString());
337        }
338    });
339    return names.length !== 0;
340}
341
342/** @internal */
343export function hasEtsBuilderDecoratorNames(decorators: NodeArray<Decorator> | readonly Decorator[] | undefined, options: CompilerOptions): boolean {
344    const names: string[] = [];
345    if (!decorators || !decorators.length) {
346        return false;
347    }
348    const renderDecorators: string[] | undefined = options?.ets?.render?.decorator;
349    if (!(renderDecorators && renderDecorators.length)) {
350        return false;
351    }
352    decorators.forEach(decorator => {
353        const nameExpr = decorator.expression;
354        if (isIdentifier(nameExpr) && renderDecorators.includes(nameExpr.escapedText.toString())) {
355            names.push(nameExpr.escapedText.toString());
356        }
357    });
358    return names.length !== 0;
359}
360
361/** @internal */
362export function hasEtsConcurrentDecoratorNames(decorators: NodeArray<Decorator> | readonly Decorator[] | undefined, options: CompilerOptions): boolean {
363    const names: string[] = [];
364    if (!decorators || !decorators.length) {
365        return false;
366    }
367    decorators.forEach(decorator => {
368        const nameExpr = decorator.expression;
369        if (isIdentifier(nameExpr) && nameExpr.escapedText.toString() === options.ets?.concurrent?.decorator) {
370            names.push(nameExpr.escapedText.toString());
371        }
372    });
373    return names.length !== 0;
374}
375
376/** @internal */
377export function isTokenInsideBuilder(decorators: NodeArray<Decorator> | readonly Decorator[] | undefined, compilerOptions: CompilerOptions): boolean {
378    const renderDecorators = compilerOptions.ets?.render?.decorator ?? ["Builder", "LocalBuilder"];
379
380    if (!decorators) {
381        return false;
382    }
383
384    if (!(renderDecorators && renderDecorators.length)) {
385        return false;
386    }
387
388    for (const decorator of decorators) {
389        if (isIdentifier(decorator.expression) && renderDecorators.includes((<Identifier>(decorator.expression)).escapedText.toString())) {
390            return true;
391        }
392    }
393    return false;
394}
395
396/** @internal */
397export function getEtsComponentExpressionInnerCallExpressionNode(node: Node | undefined): EtsComponentExpression | undefined {
398    while (node && node.kind !== SyntaxKind.EtsComponentExpression) {
399        if (node.kind === SyntaxKind.CallExpression) {
400            node = (<CallExpression>node).expression;
401        }
402        else if (node.kind === SyntaxKind.PropertyAccessExpression) {
403            node = (<PropertyAccessExpression>node).expression;
404        }
405        else {
406            node = undefined;
407        }
408    }
409    return <EtsComponentExpression>node;
410}
411
412/** @internal */
413export function getRootEtsComponentInnerCallExpressionNode(node: Node | undefined): EtsComponentExpression | undefined {
414    if (node && isEtsComponentExpression(node)) {
415        return node;
416    }
417
418    while (node) {
419        const ancestor = <CallExpression>getAncestor(isCallExpression(node) ? node.parent : node, SyntaxKind.CallExpression);
420        const target = getRootEtsComponent(ancestor);
421        if (target && isInStateStylesObject(node)) {
422            return target;
423        }
424        node = ancestor ?? node.parent;
425    }
426
427    return undefined;
428}
429
430/** @internal */
431export function getEtsComponentExpressionInnerExpressionStatementNode(node: Node | undefined): CallExpression | EtsComponentExpression | PropertyAccessExpression | undefined {
432    while (node && !isIdentifier(node)) {
433        const parent = node;
434        const currentNode = (node as ExpressionStatement | CallExpression | PropertyAccessExpression | EtsComponentExpression).expression;
435        if (currentNode && isIdentifier(currentNode)) {
436            node = parent;
437            break;
438        }
439        else {
440            node = currentNode;
441        }
442    }
443    if (!node) {
444        return undefined;
445    }
446    if (isCallExpression(node) || isEtsComponentExpression(node) || isPropertyAccessExpression(node)) {
447        return node;
448    }
449    return undefined;
450}
451
452/** @internal */
453function isInStateStylesObject(node: Node | undefined): boolean {
454    const ancestor = <ObjectLiteralExpression>getAncestor(node, SyntaxKind.ObjectLiteralExpression);
455    return ancestor !== undefined && ancestor.parent !== undefined && isPropertyAssignment(ancestor.parent);
456}
457
458/** @internal */
459export function getEtsExtendDecoratorsComponentNames(decorators: NodeArray<Decorator> | readonly Decorator[] | undefined, compilerOptions: CompilerOptions): __String[] {
460    const extendComponents: __String[] = [];
461    const extendDecorator = compilerOptions.ets?.extend?.decorator ?? "Extend";
462    decorators?.forEach((decorator) => {
463        if (decorator.expression.kind === SyntaxKind.CallExpression) {
464            const identifier = (<CallExpression>decorator.expression).expression;
465            const args = (<CallExpression>decorator.expression).arguments;
466            if (identifier.kind === SyntaxKind.Identifier && extendDecorator?.includes((<Identifier>identifier).escapedText.toString()) && args.length) {
467                // only read @Extend(...args) first argument
468                if (args[0].kind === SyntaxKind.Identifier) {
469                    extendComponents.push((<Identifier>args[0]).escapedText);
470                }
471            }
472        }
473    });
474    return extendComponents;
475}
476
477/** @internal */
478export function getEtsStylesDecoratorComponentNames(decorators: NodeArray<Decorator> | readonly Decorator[] | undefined, compilerOptions: CompilerOptions): __String[] {
479    const stylesComponents: __String[] = [];
480    const stylesDecorator = compilerOptions.ets?.styles?.decorator ?? "Styles";
481    decorators?.forEach(decorator => {
482        if (decorator.kind === SyntaxKind.Decorator && decorator.expression.kind === SyntaxKind.Identifier) {
483            const identifier = <Identifier>decorator.expression;
484            if (identifier.kind === SyntaxKind.Identifier && identifier.escapedText === stylesDecorator) {
485                stylesComponents.push(identifier.escapedText);
486            }
487        }
488    });
489    return stylesComponents;
490}
491
492/** @internal */
493export function filterEtsExtendDecoratorComponentNamesByOptions(decoratorComponentNames: __String[], compilerOptions: CompilerOptions): __String[] {
494    if (!decoratorComponentNames.length) {
495        return [];
496    }
497    const filtered: __String[] = [];
498    compilerOptions.ets?.extend.components.forEach(({ name }) => {
499        if (name === last(decoratorComponentNames)) {
500            filtered.push(name);
501        }
502    });
503    return filtered;
504}
505
506export function getTypeExportImportAndConstEnumTransformer(context: TransformationContext): (node: SourceFile) => SourceFile {
507    return transformTypeExportImportAndConstEnumInTypeScript(context);
508}
509
510export function getAnnotationTransformer(): TransformerFactory<SourceFile> {
511    return (context: TransformationContext) => transformAnnotation(context);
512}
513
514export function transformAnnotation(context: TransformationContext): (node: SourceFile) => SourceFile {
515    const resolver = context.getEmitResolver();
516
517    return transformSourceFile;
518
519    function transformSourceFile(node: SourceFile): SourceFile {
520        if (node.isDeclarationFile) {
521            return node;
522        }
523        // Firstly, visit declarations
524        const updatedSource = factory.updateSourceFile(node,
525            visitLexicalEnvironment(node.statements, visitAnnotationsDeclarations, context));
526        // Secondly, visit import and usage of annotations
527        return factory.updateSourceFile(
528            node,
529            visitLexicalEnvironment(updatedSource.statements, visitAnnotations, context));
530    }
531
532    function visitAnnotationsDeclarations(node: Node): VisitResult<Node> {
533        switch (node.kind) {
534            case SyntaxKind.AnnotationDeclaration:
535                return visitAnnotationDeclaration(<AnnotationDeclaration>node);
536            default:
537                return visitEachChild(node, visitAnnotationsDeclarations, context);
538        }
539    }
540
541    function visitAnnotations(node: Node): VisitResult<Node> {
542        switch (node.kind) {
543            case SyntaxKind.ImportSpecifier:
544                return visitImportSpecifier(<ImportSpecifier>node);
545            case SyntaxKind.Decorator:
546                return visitAnnotation(<Annotation>node);
547            default:
548                return visitEachChild(node, visitAnnotations, context);
549        }
550    }
551
552    function visitImportSpecifier(node: ImportSpecifier): VisitResult<ImportSpecifier> {
553        // Return if the import has type or not refered to Annotation
554        if (node.isTypeOnly || !resolver.isReferredToAnnotation(node)) {
555            return node;
556        }
557        const magicPrefixName = addMagicPrefixToAnnotationNameIdentifier(node.name);
558        Debug.assert(isIdentifier(magicPrefixName));
559        // Add magic prefix for import Annotation. For example,
560        // import {Anno} from "xxx" ---> import {__$$ETS_ANNOTATION$$__Anno} from "xxx"
561        return factory.updateImportSpecifier(node, node.isTypeOnly, node.propertyName, magicPrefixName);
562    }
563
564    function visitAnnotationDeclaration(node: AnnotationDeclaration): VisitResult<AnnotationDeclaration> {
565        // Add magic prefix for AnnotationDeclaration. For example,
566        // @interface Anno {} ---> @interface __$$ETS_ANNOTATION$$__Anno {}
567        const magicPrefixName = addMagicPrefixToAnnotationNameIdentifier(node.name);
568        Debug.assert(isIdentifier(magicPrefixName));
569        // Add explicit type annotation and initializer. For example,
570        // @interface Anno {
571        //     a = 10 + 5
572        // }
573        //
574        // will be transformed to
575        //
576        // @interface __$$ETS_ANNOTATION$$__Anno {
577        //     a: number = 15
578        // }
579        const members = node.members.map((node: AnnotationPropertyDeclaration) => {
580            const type = resolver.getAnnotationPropertyInferredType(node);
581            const initializer = resolver.getAnnotationPropertyEvaluatedInitializer(node);
582            return factory.updateAnnotationPropertyDeclaration(node, node.name, type, initializer);
583        });
584
585        return factory.updateAnnotationDeclaration(node, node.modifiers, magicPrefixName, members);
586    }
587
588    function visitAnnotation(node: Annotation): VisitResult<Annotation> {
589        if (!node.annotationDeclaration) {
590            return node;
591        }
592        // Add default values into annotation object literal. For example,
593        // @interface Anno {
594        //     a: number = 10
595        //     b: string
596        // }
597        //
598        // @Anno({b: "abc"}) --- > @Anno({a: 10, b: "abc"})
599        // class C {}
600        //
601        // and
602        //
603        // Add the magic prefix for annotation name. For example,
604        // @myModule.Anno({a: 10, b: "abc"}) --- > @myModule.__$$ETS_ANNOTATION$$__Anno({a: 10, b: "abc"})
605        return factory.updateDecorator(
606            node,
607            addMagicPrefixToAnnotationNameIdentifier(addDefaultValuesIntoAnnotationObjectLiteral(node)),
608            node.annotationDeclaration
609        );
610    }
611
612    function addMagicPrefixToAnnotationNameIdentifier(expr: Expression): Identifier | PropertyAccessExpression | CallExpression {
613        switch (expr.kind) {
614            case SyntaxKind.Identifier:
615                return factory.createIdentifier(
616                    annotationMagicNamePrefix + (expr as Identifier).escapedText
617                );
618            case SyntaxKind.PropertyAccessExpression:
619                const propAccessExpr = expr as PropertyAccessExpression;
620                return factory.updatePropertyAccessExpression(
621                    propAccessExpr,
622                    propAccessExpr.expression,
623                    addMagicPrefixToAnnotationNameIdentifier(propAccessExpr.name) as Identifier
624                );
625            case SyntaxKind.CallExpression:
626                const callExpr = expr as CallExpression;
627                return factory.updateCallExpression(
628                    callExpr,
629                    addMagicPrefixToAnnotationNameIdentifier(callExpr.expression),
630                    callExpr.typeArguments,
631                    callExpr.arguments
632                );
633            default:
634                return expr as (Identifier | PropertyAccessExpression | CallExpression);
635        }
636    }
637
638    function addDefaultValuesIntoAnnotationObjectLiteral(annotation: Annotation): CallExpression {
639        Debug.assert(annotation.annotationDeclaration);
640        const members = annotation.annotationDeclaration.members;
641        if (isIdentifier(annotation.expression) ||
642            isPropertyAccessExpression(annotation.expression) ||
643            (isCallExpression(annotation.expression) && annotation.expression.arguments.length === 0)) {
644            const defaultValues = new Array<PropertyAssignment>(members.length);
645            for (let i = 0; i < members.length; ++i) {
646                const member = members[i] as AnnotationPropertyDeclaration;
647                const initializer = resolver.getAnnotationPropertyEvaluatedInitializer(member);
648                Debug.assert(initializer !== undefined);
649                defaultValues[i] = factory.createPropertyAssignment(member.name, initializer!);
650            }
651            const newCallExpr = factory.createCallExpression(
652                annotation.expression,
653                /* typeArguments */ undefined,
654                [factory.createObjectLiteralExpression(defaultValues, false)]);
655            return newCallExpr;
656        }
657        else if (isCallExpression(annotation.expression)) {
658            Debug.assert(annotation.expression.arguments.length === 1);
659            const obj = annotation.expression.arguments[0] as ObjectLiteralExpression;
660            const objPropNameToProp = new Map<__String, PropertyAssignment>();
661            obj.properties.forEach(p => {
662                Debug.assert(isPropertyAssignment(p));
663                objPropNameToProp.set(tryGetTextOfPropertyName(p.name)!, p);
664            });
665
666            const defaultValues = new Array<PropertyAssignment>(members.length);
667            for (let i = 0; i < members.length; ++i) {
668                const member = members[i] as AnnotationPropertyDeclaration;
669                const memberName = tryGetTextOfPropertyName(member.name)!;
670                if (objPropNameToProp.has(memberName)) {
671                    const evaluatedProps = resolver.getAnnotationObjectLiteralEvaluatedProps(annotation);
672                    Debug.assert(evaluatedProps !== undefined);
673                    defaultValues[i] = factory.createPropertyAssignment(member.name, evaluatedProps.get(memberName)!);
674                }
675                else {
676                    const evaluatedInitializer = resolver.getAnnotationPropertyEvaluatedInitializer(member);
677                    Debug.assert(evaluatedInitializer !== undefined);
678                    defaultValues[i] = factory.createPropertyAssignment(member.name, evaluatedInitializer);
679                }
680            }
681            const newCallExpr = factory.updateCallExpression(
682                annotation.expression,
683                annotation.expression.expression,
684                /* typeArguments */ undefined,
685                [factory.updateObjectLiteralExpression(obj, defaultValues)]);
686            return newCallExpr;
687        }
688        Debug.fail();
689    }
690}
691
692/**
693 * Add 'type' flag to import/export when import/export an type member.
694 * Replace const enum with number and string literal.
695 */
696export function transformTypeExportImportAndConstEnumInTypeScript(context: TransformationContext): (node: SourceFile) => SourceFile {
697    const resolver = context.getEmitResolver();
698    interface ImportInfo {
699        name: Identifier | undefined,
700        namespaceImport: NamespaceImport | undefined,
701        namedImports: ImportSpecifier[]
702    };
703    interface ExportInfo {
704        namedExports: ExportSpecifier[]
705    };
706
707    // recore type import/export info to create new import/export type statement
708    let currentTypeImportInfo: ImportInfo;
709    let currentTypeExportInfo: ExportInfo;
710
711    return transformSourceFile;
712
713    function transformSourceFile(node: SourceFile): SourceFile {
714        if (node.isDeclarationFile) {
715            return node;
716        }
717        const visited = factory.updateSourceFile(
718            node,
719            visitLexicalEnvironment(node.statements, visitImportExportAndConstEnumMember, context));
720        return visited;
721    }
722
723    function visitImportExportAndConstEnumMember(node: Node): VisitResult<Node> {
724        switch (node.kind) {
725            case SyntaxKind.ImportDeclaration:
726                return visitImportDeclaration(<ImportDeclaration>node);
727            case SyntaxKind.ImportEqualsDeclaration:
728                return visitImportEqualsDeclaration(<ImportEqualsDeclaration>node);
729            case SyntaxKind.ExportDeclaration:
730                return visitExportDeclaration(<ExportDeclaration>node);
731            case SyntaxKind.PropertyAccessExpression:
732            case SyntaxKind.ElementAccessExpression:
733                return visitConstEnum(<PropertyAccessExpression | ElementAccessExpression>node);
734            case SyntaxKind.EnumMember:
735                return visitEnumMember(<EnumMember>node);
736            default:
737                return visitEachChild(node, visitImportExportAndConstEnumMember, context);
738        }
739    }
740
741    /**
742     * Transform:
743     *
744     * import a, {b, c} from ...
745     *
746     * To:
747     *
748     * import {b} from ...
749     * import type a from ...
750     * import type {c} from ...
751     *
752     * when 'a' and 'c' are type.
753     */
754    function visitImportDeclaration(node: ImportDeclaration): VisitResult<Statement> {
755        // return if the import already has 'type'
756        if (!node.importClause || node.importClause.isTypeOnly) {
757            return node;
758        }
759        resetcurrentTypeImportInfo();
760        const res: Statement[] = [];
761        const importClause = visitNode(node.importClause, visitImportClause, isImportClause);
762        if (importClause) {
763            res.push(factory.updateImportDeclaration(node, /*modifiers*/ undefined,
764                importClause, node.moduleSpecifier, /*assertClause*/ undefined));
765        }
766        // create new import statement with 'type'
767        const typeImportClauses = createTypeImportClause();
768        for (const typeImportClause of typeImportClauses) {
769            res.push(factory.createImportDeclaration(/*modifiers*/ undefined,
770                typeImportClause, node.moduleSpecifier));
771        }
772        return res.length > 0 ? res : undefined;
773    }
774
775    function visitImportClause(node: ImportClause): VisitResult<ImportClause> {
776        if (node.isTypeOnly) {
777            return node;
778        }
779        let name: Identifier | undefined;
780        if (resolver.isReferencedAliasDeclaration(node)) {
781            name = node.name;
782        }
783        // consider it is a type if the symbol has referenced.
784        else if (resolver.isReferenced(node)) {
785            addTypeImportClauseName(node);
786        }
787        const namedBindings = visitNode(node.namedBindings, visitNamedImportBindings, isNamedImportBindings);
788        return (name || namedBindings) ?
789            factory.updateImportClause(node, /*isTypeOnly*/ false, name, namedBindings) :
790            undefined;
791    }
792
793    function visitNamedImportBindings(node: NamedImportBindings): VisitResult<NamedImportBindings> {
794        if (node.kind === SyntaxKind.NamespaceImport) {
795            if (resolver.isReferencedAliasDeclaration(node)) {
796                return node;
797            }
798            if (resolver.isReferenced(node)) {
799                addTypeNamespaceImport(node);
800            }
801            return undefined;
802        }
803        else {
804            const elements = visitNodes(node.elements, visitImportSpecifier, isImportSpecifier);
805            return some(elements) ? factory.updateNamedImports(node, elements) : undefined;
806        }
807    }
808
809    function visitImportSpecifier(node: ImportSpecifier): VisitResult<ImportSpecifier> {
810        if (node.isTypeOnly) {
811            return node;
812        }
813        if (resolver.isReferencedAliasDeclaration(node)) {
814            return node;
815        }
816        if (resolver.isReferenced(node)) {
817            addTypeImportSpecifier(node);
818        }
819        return undefined;
820    }
821
822    function addTypeImportClauseName(node: ImportClause): void {
823        currentTypeImportInfo.name = node.name;
824    }
825
826    function addTypeNamespaceImport(node: NamespaceImport): void {
827        currentTypeImportInfo.namespaceImport = node;
828    }
829
830    function addTypeImportSpecifier(node: ImportSpecifier): void {
831        currentTypeImportInfo.namedImports.push(node);
832    }
833
834    /**
835     * Create new import type statement, like:
836     * import type {a} from ...
837     */
838    function createTypeImportClause(): ImportClause[] {
839        const name: Identifier | undefined = currentTypeImportInfo.name;
840        let namedBindings: NamedImportBindings | undefined;
841        if (currentTypeImportInfo.namespaceImport) {
842            namedBindings = currentTypeImportInfo.namespaceImport;
843        }
844        else if (currentTypeImportInfo.namedImports.length > 0) {
845            namedBindings = factory.createNamedImports(currentTypeImportInfo.namedImports);
846        }
847        const typeImportClauses: ImportClause[] = [];
848        if (name !== undefined) {
849            typeImportClauses.push(factory.createImportClause(/*isTypeOnly*/ true, name, /*namedBindings*/ undefined));
850        }
851        if (namedBindings !== undefined) {
852            typeImportClauses.push(factory.createImportClause(/*isTypeOnly*/ true, /*name*/ undefined, namedBindings));
853        }
854        resetcurrentTypeImportInfo();
855        return typeImportClauses;
856    }
857
858    /**
859     * Transform:
860     *
861     * import a = require(...)
862     *
863     * To:
864     *
865     * import type a = require(...)
866     *
867     * when 'a' is type.
868     */
869    function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult<Statement> {
870        // return if the import already has 'type'
871        if (node.isTypeOnly) {
872            return node;
873        }
874
875        if (isExternalModuleImportEqualsDeclaration(node)) {
876            const isReferenced = resolver.isReferencedAliasDeclaration(node);
877            if (isReferenced) {
878                return node;
879            }
880            if (resolver.isReferenced(node)) {
881                return factory.updateImportEqualsDeclaration(node, node.modifiers,
882                    /*isTypeOnly*/ true, node.name, node.moduleReference);
883            }
884
885            return undefined;
886        }
887
888        return node;
889    }
890
891    /**
892     * Transform:
893     *
894     * export {a}
895     *
896     * To:
897     *
898     * export type {a}
899     *
900     * when 'a' is type.
901     */
902    function visitExportDeclaration(node: ExportDeclaration): VisitResult<Statement> {
903        // return if the export already has 'type'or export *
904        if (node.isTypeOnly || !node.exportClause || isNamespaceExport(node.exportClause)) {
905            return node;
906        }
907
908        resetcurrentTypeExportInfo();
909        const res: Statement[] = [];
910
911        const exportClause = visitNode(node.exportClause, visitNamedExports, isNamedExportBindings);
912        if (exportClause) {
913            res.push(factory.updateExportDeclaration(node, /*modifiers*/ undefined,
914                node.isTypeOnly, exportClause, node.moduleSpecifier, /*assertClause*/ undefined));
915        }
916        const typeExportClause = createTypeExportClause();
917        if (typeExportClause) {
918            res.push(factory.createExportDeclaration(/*modifiers*/ undefined,
919                /*isTypeOnly*/ true, typeExportClause, node.moduleSpecifier));
920        }
921
922        return res.length > 0 ? res : undefined;
923    }
924
925    function visitNamedExports(node: NamedExports): VisitResult<NamedExports> {
926        const elements = visitNodes(node.elements, visitExportSpecifier, isExportSpecifier);
927        return some(elements) ? factory.updateNamedExports(node, elements) : undefined;
928    }
929
930    function visitExportSpecifier(node: ExportSpecifier): VisitResult<ExportSpecifier> {
931        if (node.isTypeOnly) {
932            return node;
933        }
934        if (resolver.isValueAliasDeclaration(node)) {
935            return node;
936        }
937        // consider all rest member are type.
938        addTypeExportSpecifier(node);
939        return undefined;
940    }
941
942    function addTypeExportSpecifier(node: ExportSpecifier): void {
943        currentTypeExportInfo.namedExports.push(node);
944    }
945
946    /**
947     * Create new export type statement, like:
948     * export type {a}
949     */
950    function createTypeExportClause(): NamedExports | undefined {
951        let namedBindings: NamedExports | undefined;
952        if (currentTypeExportInfo.namedExports.length > 0) {
953            namedBindings = factory.createNamedExports(currentTypeExportInfo.namedExports);
954        }
955        resetcurrentTypeExportInfo();
956        return namedBindings;
957    }
958
959    function visitConstEnum(node: PropertyAccessExpression | ElementAccessExpression): LeftHandSideExpression {
960        const constantValue = resolver.getConstantValue(node);
961        if (constantValue !== undefined) {
962            const substitute = typeof constantValue === "string" ?
963                factory.createStringLiteral(constantValue) :
964                factory.createNumericLiteral(constantValue);
965            return substitute;
966        }
967
968        return visitEachChild(node, visitImportExportAndConstEnumMember, context);
969    }
970
971    /**
972     * If the enum member is a const value, replace it.
973     */
974    function visitEnumMember(node: EnumMember): VisitResult<EnumMember> {
975        const value = resolver.getConstantValue(node);
976        if (value !== undefined) {
977            const substitute = typeof value === "string" ?
978                factory.createStringLiteral(value) :
979                factory.createNumericLiteral(value);
980            return factory.updateEnumMember(node, node.name, substitute);
981        }
982        return visitEachChild(node, visitImportExportAndConstEnumMember, context);
983    }
984
985    function resetcurrentTypeImportInfo(): void {
986        currentTypeImportInfo = { name: undefined, namespaceImport: undefined, namedImports:[] };
987    }
988
989    function resetcurrentTypeExportInfo(): void {
990        currentTypeExportInfo = { namedExports:[] };
991    }
992}
993
994export function hasTsNoCheckOrTsIgnoreFlag(node: SourceFile): boolean {
995    // check @ts-nocheck flag
996    if (!!node.checkJsDirective && node.checkJsDirective.enabled === false) {
997        return true;
998    }
999    // check @ts-ignore flag
1000    if (node.commentDirectives !== undefined) {
1001        for (const commentDirective of node.commentDirectives) {
1002            if (commentDirective.type === CommentDirectiveType.Ignore) {
1003                return true;
1004            }
1005        }
1006    }
1007    return false;
1008}
1009
1010export function createObfTextSingleLineWriter(): EmitTextWriter {
1011    const space: string = " ";
1012    let output: string;
1013    let lineStart: boolean;
1014    let linePos: number;
1015    let lineCount: number;
1016    // If the last character of string is the one of below chars, there is no need to write space again.
1017    const noSpaceTrailingChars: Set<string> = new Set([' ', ';', ',', '(', ')', '{', '}']);
1018
1019    function updateLineCountAndPosFor(s: string) {
1020        const lineStartsOfS = computeLineStarts(s);
1021        if (lineStartsOfS.length > 1) {
1022            // 1: The first element of the lineStartsOfS
1023            lineCount = lineCount + lineStartsOfS.length - 1;
1024            linePos = output.length - s.length + last(lineStartsOfS);
1025            lineStart = (linePos - output.length) === 0;
1026        }
1027        else {
1028            lineStart = false;
1029        }
1030    }
1031
1032    function writeText(s: string) {
1033        if (s && s.length) {
1034            if (lineStart) {
1035                lineStart = false;
1036            }
1037            output += s;
1038            updateLineCountAndPosFor(s);
1039        }
1040    }
1041
1042    function write(s: string) {
1043        writeText(s);
1044    }
1045
1046    function reset(): void {
1047        output = "";
1048        lineStart = true;
1049        linePos = 0;
1050        lineCount = 0;
1051    }
1052
1053        // This method is used to write indentation and line breaks. If the string is blank, the writing is skipped.
1054        // In addition, this method can be called to write comments and code in bundle mode, but obfuscation is not in bundle mode.
1055    function rawWrite(s: string) {
1056        if (s !== undefined) {
1057            if ((lineStart || endsWithNoSpaceTrailingChar(output)) && s.trim().length === 0) {
1058                return;
1059            }
1060            output += s;
1061            updateLineCountAndPosFor(s);
1062        }
1063    }
1064
1065    function writeLiteral(s: string) {
1066        if (s && s.length) {
1067            write(s);
1068        }
1069    }
1070
1071    function writeLine(force?: boolean): void {
1072        if (!force && (lineStart || endsWithNoSpaceTrailingChar(output))) {
1073            return;
1074        }
1075        output += space;
1076        lineStart = false;
1077    }
1078
1079    function endsWithNoSpaceTrailingChar(input: string): boolean {
1080        // Get the last character of a string.
1081        const lastChar: string = input.charAt(input.length - 1);
1082        return noSpaceTrailingChars.has(lastChar);
1083    }
1084
1085    function getTextPosWithWriteLine() {
1086        return lineStart ? output.length : (output.length + space.length);
1087    }
1088
1089    reset();
1090
1091    return {
1092        write,
1093        rawWrite,
1094        writeLiteral,
1095        writeLine,
1096        increaseIndent: noop,
1097        decreaseIndent: noop,
1098        getIndent: () => 0,
1099        getTextPos: () => output.length,
1100        getLine: () => lineCount,
1101        getColumn: () => lineStart ? 0 : output.length - linePos,
1102        getText: () => output,
1103        isAtStartOfLine: () => lineStart,
1104        hasTrailingComment: () => false,
1105        hasTrailingWhitespace: () => !!output.length && isWhiteSpaceLike(output.charCodeAt(output.length - 1)),
1106        clear: reset,
1107        reportInaccessibleThisError: noop,
1108        reportPrivateInBaseOfClassExpression: noop,
1109        reportInaccessibleUniqueSymbolError: noop,
1110        trackSymbol: () => false,
1111        writeKeyword: write,
1112        writeOperator: write,
1113        writeParameter: write,
1114        writeProperty: write,
1115        writePunctuation: write,
1116        writeSpace: write,
1117        writeStringLiteral: write,
1118        writeSymbol: (s, _) => write(s),
1119        writeTrailingSemicolon: write,
1120        writeComment: noop,
1121        getTextPosWithWriteLine
1122    };
1123}
1124
1125/** @internal */
1126export function isSendableFunctionOrType(node: Node, maybeNotOriginalNode: boolean = false): boolean {
1127    if (!node || !(isFunctionDeclaration(node) || isTypeAliasDeclaration(node))) {
1128        return false;
1129    }
1130    if (!isInEtsFile(node) && !(maybeNotOriginalNode && isInEtsFileWithOriginal(node))) {
1131        return false;
1132    }
1133    const illegalDecorators = getIllegalDecorators(node);
1134    if (!illegalDecorators || illegalDecorators.length !== 1) {
1135        return false;
1136    }
1137    const nameExpr = illegalDecorators[0].expression;
1138    return (isIdentifier(nameExpr) && nameExpr.escapedText.toString() === 'Sendable');
1139}
1140
1141/** @internal */
1142export function checkStructPropertyPosition(declaration: Node, prop: Node): boolean {
1143    // Struct can't be declared inside another struct, so if the parent of PropertyDeclaration node is StructDeclaration
1144    // and its end position is behind the end position of PropertyDeclaration node, we can make sure the property is declared and used in the same struct.
1145    return declaration.pos < prop.pos && isStructDeclaration(declaration.parent) && declaration.parent.end > prop.end;
1146}
1147
1148export const REQUIRE_DECORATOR = 'Require';
1149const JSON_SUFFIX = '.json';
1150const KIT_PREFIX = '@kit.';
1151const DEFAULT_KEYWORD = 'default';
1152const ETS_DECLARATION = '.d.ets';
1153export const THROWS_TAG = 'throws';
1154export const THROWS_CATCH = 'catch';
1155export const THROWS_ASYNC_CALLBACK = 'AsyncCallback';
1156export const THROWS_ERROR_CALLBACK = 'ErrorCallback';
1157
1158interface KitSymbolInfo {
1159    source: string,
1160    bindings: string,
1161}
1162
1163interface KitJsonInfo {
1164    symbols: {
1165        [symbol: string]: KitSymbolInfo,
1166    }
1167}
1168
1169const kitJsonCache = new Map<string, KitJsonInfo | undefined>();
1170
1171/** @internal */
1172export function getSdkPath(compilerOptions: CompilerOptions): string | undefined {
1173    if (isMixedCompilerSDKPath(compilerOptions)) {
1174        return resolvePath(compilerOptions.etsLoaderPath!, '../../../../..');
1175    }
1176    return compilerOptions.etsLoaderPath ? resolvePath(compilerOptions.etsLoaderPath, '../../../..') : undefined;
1177}
1178
1179function getKitJsonObject(name: string, sdkPath: string, compilerOptions: CompilerOptions): KitJsonInfo | undefined {
1180    if (kitJsonCache?.has(name)) {
1181        return kitJsonCache.get(name);
1182    }
1183    const OHOS_KIT_CONFIG_PATH = isMixedCompilerSDKPath(compilerOptions) ?
1184        './openharmony/ets/ets1.1/build-tools/ets-loader/kit_configs' :
1185        './openharmony/ets/build-tools/ets-loader/kit_configs';
1186    const HMS_KIT_CONFIG_PATH = isMixedCompilerSDKPath(compilerOptions) ?
1187        './hms/ets/ets1.1/build-tools/ets-loader/kit_configs' :
1188        './hms/ets/build-tools/ets-loader/kit_configs';
1189    const ohosJsonPath = resolvePath(sdkPath, OHOS_KIT_CONFIG_PATH, `./${name}${JSON_SUFFIX}`);
1190    const hmsJsonPath = resolvePath(sdkPath, HMS_KIT_CONFIG_PATH, `./${name}${JSON_SUFFIX}`);
1191
1192    let fileInfo: string | undefined =
1193        sys.fileExists(ohosJsonPath) ? sys.readFile(ohosJsonPath, 'utf-8') :
1194        sys.fileExists(hmsJsonPath) ? sys.readFile(hmsJsonPath, 'utf-8') :
1195        undefined;
1196    if (!fileInfo) {
1197        kitJsonCache?.set(name, undefined);
1198        return undefined;
1199    }
1200
1201    const obj = JSON.parse(fileInfo) as KitJsonInfo;
1202    kitJsonCache?.set(name, obj);
1203
1204    return obj;
1205}
1206
1207// Determine if it is a 1.2 SDK path
1208export function isMixedCompilerSDKPath(compilerOptions: CompilerOptions): boolean {
1209    if (!compilerOptions.etsLoaderPath) {
1210        return false;
1211    }
1212    if (normalizePath(compilerOptions.etsLoaderPath).endsWith('ets1.1/build-tools/ets-loader')) {
1213        return true;
1214    }
1215    return false;
1216}
1217
1218export function cleanKitJsonCache(): void {
1219    kitJsonCache?.clear();
1220}
1221
1222function setVirtualNodeAndKitImportFlags<T extends Node>(node: T, start: number = 0, end: number = 0): T {
1223    node.virtual = true;
1224    setTextRangePosEnd(node, start, end);
1225    (node as Mutable<T>).flags |= NodeFlags.KitImportFlags;
1226    return node;
1227}
1228
1229function setNoOriginalText<T extends Node>(node: T): T {
1230    (node as Mutable<T>).flags |= NodeFlags.NoOriginalText;
1231    return node;
1232}
1233
1234function createNameImportDeclaration(factory: NodeFactory, isType: boolean, name: Identifier, source: string,
1235    oldStatement: ImportDeclaration, importSpecifier: TextRange, isLazy?: boolean): ImportDeclaration {
1236    const oldModuleSpecifier = oldStatement.moduleSpecifier;
1237    const newModuleSpecifier = setNoOriginalText(setVirtualNodeAndKitImportFlags(
1238        factory.createStringLiteral(source), oldModuleSpecifier.pos, oldModuleSpecifier.end)
1239    );
1240    let newImportClause = factory.createImportClause(isType, name, undefined);
1241    // Add the isLazy flag in the original importDeclaration to the new importClause statement.
1242    (newImportClause as Mutable<ImportClause>).isLazy = isLazy;
1243    newImportClause = setVirtualNodeAndKitImportFlags(newImportClause, importSpecifier.pos, importSpecifier.end);
1244    const newImportDeclaration = setVirtualNodeAndKitImportFlags(
1245        factory.createImportDeclaration(undefined, newImportClause, newModuleSpecifier), oldStatement.pos, oldStatement.end);
1246    return newImportDeclaration;
1247}
1248
1249function createBindingImportDeclaration(factory: NodeFactory, isType: boolean, propname: string, name: Identifier, source: string,
1250    oldStatement: ImportDeclaration, importSpecifier: TextRange, isLazy?: boolean): ImportDeclaration {
1251    const oldModuleSpecifier = oldStatement.moduleSpecifier;
1252    const newModuleSpecifier = setNoOriginalText(
1253        setVirtualNodeAndKitImportFlags(factory.createStringLiteral(source), oldModuleSpecifier.pos, oldModuleSpecifier.end));
1254    const newPropertyName = setNoOriginalText(setVirtualNodeAndKitImportFlags(factory.createIdentifier(propname), name.pos, name.end));
1255    // The location information of the newImportSpecific is created using the location information of the old importSpecifier.
1256    const newImportSpecific = setVirtualNodeAndKitImportFlags(
1257        factory.createImportSpecifier(false, newPropertyName, name), importSpecifier.pos, importSpecifier.end);
1258    // The location information of the newNamedBindings is created using the location information of the old importSpecifier.
1259    const newNamedBindings = setVirtualNodeAndKitImportFlags(factory.createNamedImports([newImportSpecific]), importSpecifier.pos, importSpecifier.end);
1260    let newImportClause = factory.createImportClause(isType, undefined, newNamedBindings);
1261    // Add the isLazy flag in the original importDeclaration to the new importClause statement.
1262    (newImportClause as Mutable<ImportClause>).isLazy = isLazy;
1263    // The location information of the newImportClause is created using the location information of the old importSpecifier.
1264    newImportClause = setVirtualNodeAndKitImportFlags(
1265        newImportClause, importSpecifier.pos, importSpecifier.end);
1266    const newImportDeclaration = setVirtualNodeAndKitImportFlags(
1267        factory.createImportDeclaration(undefined, newImportClause, newModuleSpecifier), oldStatement.pos, oldStatement.end);
1268    return newImportDeclaration;
1269}
1270
1271function createImportDeclarationForKit(factory: NodeFactory, isType: boolean, name: Identifier, symbol: KitSymbolInfo,
1272    oldStatement: ImportDeclaration, importSpecifier: TextRange, isLazy?: boolean): ImportDeclaration {
1273    const source = symbol.source.replace(/\.d.[e]?ts$/, '');
1274    const binding = symbol.bindings;
1275    if (binding === DEFAULT_KEYWORD) {
1276        return createNameImportDeclaration(factory, isType, name, source, oldStatement, importSpecifier, isLazy);
1277    }
1278    return createBindingImportDeclaration(factory, isType, binding, name, source, oldStatement, importSpecifier, isLazy);
1279}
1280
1281function markKitImport(statement : Statement, markedkitImportRanges: Array<TextRange>): void {
1282    markedkitImportRanges.push({ pos: statement.pos, end: statement.end });
1283}
1284
1285/** @internal */
1286export function isInMarkedKitImport(sourceFile: SourceFile, pos: number, end: number): boolean {
1287    return !!sourceFile.markedKitImportRange?.some(
1288        range => {
1289            return (range.pos <= pos) && (end <= range.end);
1290        }
1291    );
1292}
1293
1294function excludeStatementForKitImport(statement: Statement): boolean {
1295    if (!isImportDeclaration(statement) || // check is ImportDeclaration
1296        !statement.importClause || // exclude import 'mode'
1297        (statement.importClause.namedBindings && isNamespaceImport(statement.importClause.namedBindings)) || // exclude namespace import
1298        !isStringLiteral(statement.moduleSpecifier) || statement.illegalDecorators || // exclude if may has error
1299        !statement.moduleSpecifier.text.startsWith(KIT_PREFIX) || // is not kit import
1300        statement.modifiers || // exclude if has modifiers
1301        statement.assertClause) { // not support assertClause
1302        return true;
1303    }
1304    return false;
1305}
1306
1307interface WhiteListInfo {
1308    kitName: string;
1309    symbolName: string;
1310}
1311// This symbols have error in kit files, so add it in white list and don't change
1312const whiteListForErrorSymbol: WhiteListInfo[] = [
1313    { kitName: '@kit.CoreFileKit', symbolName: 'DfsListeners' },
1314    { kitName: '@kit.NetworkKit', symbolName: 'VpnExtensionContext' },
1315    { kitName: '@kit.ArkUI', symbolName: 'CustomContentDialog' },
1316];
1317
1318// This symbol will clause new warning in ts files
1319const whiteListForTsWarning: WhiteListInfo[] = [
1320    { kitName: '@kit.ConnectivityKit', symbolName: 'socket' },
1321];
1322
1323// This files import the symbol from ets file, so we won't change them in ts files
1324const whiteListForTsFile: Set<string> = new Set([
1325    '@kit.AccountKit', '@kit.MapKit', '@kit.Penkit', '@kit.ScenarioFusionKit',
1326    '@kit.ServiceCollaborationKit', '@kit.SpeechKit', '@kit.VisionKit',
1327    '@kit.PDFKit', '@kit.ReaderKit',
1328]);
1329
1330function inWhiteList(moduleSpecifierText: string, importName: string, inEtsContext: boolean): boolean {
1331    if (whiteListForErrorSymbol.some(info => (info.kitName === moduleSpecifierText && info.symbolName === importName))) {
1332        return true;
1333    }
1334    if (!inEtsContext &&
1335        whiteListForTsWarning.some(info => (info.kitName === moduleSpecifierText && info.symbolName === importName))) {
1336        return true;
1337    }
1338    return false;
1339}
1340
1341function processKitStatementSuccess(factory: NodeFactory, statement: ImportDeclaration, jsonObject: KitJsonInfo | undefined, inEtsContext: boolean,
1342    newImportStatements: Array<ImportDeclaration>): boolean {
1343    const importClause = statement.importClause!;
1344    const moduleSpecifierText = (statement.moduleSpecifier as StringLiteral).text;
1345    const kitSymbol = jsonObject?.symbols;
1346    if (!kitSymbol) {
1347        return false;
1348    }
1349
1350    const isType = importClause.isTypeOnly;
1351    const isLazy = importClause.isLazy;
1352    if (importClause.name) {
1353        const symbol = kitSymbol[DEFAULT_KEYWORD];
1354        // has error when import ets declaration in ts file
1355        if (!symbol || (!inEtsContext && symbol.source.endsWith(ETS_DECLARATION))) {
1356            return false;
1357        }
1358        newImportStatements.push(createImportDeclarationForKit(factory, isType, importClause.name, symbol, statement, importClause.name, isLazy));
1359    }
1360
1361    if (importClause.namedBindings) {
1362        let hasError = false;
1363        (importClause.namedBindings as NamedImports).elements.forEach(
1364            element => {
1365                if (hasError) {
1366                    return;
1367                }
1368                const importName = unescapeLeadingUnderscores(element.propertyName ? element.propertyName.escapedText : element.name.escapedText);
1369                const aliasName = element.name;
1370
1371                if (inWhiteList(moduleSpecifierText, importName, inEtsContext)) {
1372                    hasError = true;
1373                    return;
1374                }
1375
1376                const symbol = kitSymbol[importName];
1377                if (!symbol || !aliasName ||
1378                    // has error when import ets declaration in ts file
1379                    (!inEtsContext && symbol.source.endsWith(ETS_DECLARATION)) ||
1380                    // can not have duplicate type
1381                    (isType && element.isTypeOnly)) {
1382                    hasError = true;
1383                    return;
1384                }
1385
1386                newImportStatements.push(
1387                    createImportDeclarationForKit(factory, isType || element.isTypeOnly, aliasName, symbol, statement, element, isLazy));
1388            }
1389        );
1390        if (hasError) {
1391            return false;
1392        }
1393    }
1394    return true;
1395}
1396
1397/** @internal */
1398export function processKit(factory: NodeFactory, statements: NodeArray<Statement>, sdkPath: string,
1399    markedkitImportRanges: Array<TextRange>, inEtsContext: boolean, compilerOptions: CompilerOptions): Statement[] {
1400    const list: Statement[] = [];
1401    let skipRestStatements = false;
1402    statements.forEach(
1403        statement => {
1404            // ArkTS don't allow import declaration after other statements
1405            if (!skipRestStatements && inEtsContext && !isImportDeclaration(statement)) {
1406                skipRestStatements = true;
1407            }
1408            if (skipRestStatements || excludeStatementForKitImport(statement)) {
1409                list.push(statement);
1410                return;
1411            }
1412
1413            const moduleSpecifierText = ((statement as ImportDeclaration).moduleSpecifier as StringLiteral).text;
1414            if (!inEtsContext && whiteListForTsFile.has(moduleSpecifierText)) {
1415                list.push(statement);
1416                return;
1417            }
1418
1419            const jsonObject = getKitJsonObject(moduleSpecifierText, sdkPath, compilerOptions);
1420            const newImportStatements = new Array<ImportDeclaration>();
1421
1422            if (!processKitStatementSuccess(factory, statement as ImportDeclaration, jsonObject, inEtsContext, newImportStatements)) {
1423                list.push(statement);
1424                return;
1425            }
1426
1427            list.push(...newImportStatements);
1428            markKitImport(statement, markedkitImportRanges);
1429        }
1430    );
1431    return list;
1432}
1433
1434export function getMaxFlowDepth(compilerOptions: CompilerOptions): number {
1435    // The value of maxFlowDepth ranges from 2000 to 65535.
1436    return compilerOptions.maxFlowDepth || maxFlowDepthDefaultValue;
1437}
1438
1439export interface MoreInfo {
1440    cn: string,
1441    en: string
1442}
1443
1444export class ErrorInfo {
1445    code: string = '';
1446    description: string = 'ArkTS Compiler Error'; // The description of type errors for TSC
1447    cause: string = '';
1448    position: string = '';
1449    solutions: string[] = [];
1450    moreInfo?: MoreInfo;
1451
1452    getCode(): string {
1453        return this.code;
1454    }
1455
1456    getDescription(): string {
1457        return this.description;
1458    }
1459
1460    getCause(): string {
1461        return this.cause;
1462    }
1463
1464    getPosition(): string {
1465        return this.position;
1466    }
1467
1468    getSolutions(): string[] {
1469        return this.solutions;
1470    }
1471
1472    getMoreInfo(): MoreInfo | undefined {
1473        return this.moreInfo;
1474    }
1475}
1476
1477export enum ErrorCodeArea {
1478    TSC = 0,
1479    LINTER = 1,
1480    UI = 2
1481}
1482
1483const SUBSYSTEM_CODE = '105'; // Subsystem coding
1484const ERROR_TYPE_CODE = '05'; // Error type code
1485const EXTENSION_CODE = '001'; // Extended codes defined by various subsystems
1486const codeCollectionUI = new Set([28000, 28001, 28002, 28003, 28004, 28005, 28006, 28007, 28015]); // UI code error collection
1487const codeCollectionLinter = new Set([28016, 28017]); // Linter code error collection
1488const newTscCodeMap = new Map([
1489    [28014, '10505114']
1490]); // New tsc code error collection
1491
1492// Currently, only the tsc error reporting triggers this function.
1493export function getErrorCode(diagnostic: Diagnostic): ErrorInfo {
1494    let errorInfo: ErrorInfo = new ErrorInfo();
1495    errorInfo.cause = flattenDiagnosticMessageText(diagnostic.messageText, '\n');
1496
1497    if (diagnostic.file) {
1498        const { line, character }: LineAndCharacter = getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start!);
1499        errorInfo.position = `File: ${diagnostic.file.fileName}:${line + 1}:${character + 1}`;
1500    }
1501
1502    if (newTscCodeMap.has(diagnostic.code)) {
1503        errorInfo.code = newTscCodeMap.get(diagnostic.code) as string;
1504    } else {
1505        errorInfo.code = SUBSYSTEM_CODE + ERROR_TYPE_CODE + EXTENSION_CODE;
1506    }
1507    return errorInfo;
1508}
1509
1510export function getErrorCodeArea(code: number): ErrorCodeArea {
1511    if (codeCollectionLinter.has(code)) {
1512        return ErrorCodeArea.LINTER;
1513    } else if (codeCollectionUI.has(code)) {
1514        return ErrorCodeArea.UI;
1515    } else {
1516        return ErrorCodeArea.TSC;
1517    }
1518}