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