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}