1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import ts from 'typescript'; 17import fs from 'fs'; 18import path from 'path'; 19import JSON5 from 'json5'; 20 21import { 22 EXTNAME_ETS, 23 EXTNAME_TS, 24 INDEX_ETS, 25 INDEX_TS, 26 CUSTOM_COMPONENT_DEFAULT, 27 CUSTOM_DECORATOR_NAME, 28 COMPONENT_DECORATOR_ENTRY, 29 COMPONENT_BUILDER_DECORATOR, 30 DECORATOR_REUSEABLE, 31 DECORATOR_REUSABLE_V2 32} from './pre_define'; 33import { 34 propertyCollection, 35 linkCollection, 36 componentCollection, 37 preprocessExtend, 38 preprocessNewExtend, 39 processSystemApi, 40 propCollection, 41 isObservedClass, 42 isCustomDialogClass, 43 observedClassCollection, 44 enumCollection, 45 getComponentSet, 46 IComponentSet, 47 builderParamObjectCollection, 48 stateCollection, 49 regularCollection, 50 storagePropCollection, 51 storageLinkCollection, 52 provideCollection, 53 consumeCollection, 54 objectLinkCollection, 55 localStorageLinkCollection, 56 localStoragePropCollection, 57 builderParamInitialization, 58 propInitialization, 59 regularInitialization, 60 stateInitialization, 61 provideInitialization, 62 privateCollection, 63 regularStaticCollection 64} from './validate_ui_syntax'; 65import { 66 CurrentProcessFile, 67 getExtensionIfUnfullySpecifiedFilepath, 68 hasDecorator, 69 LogInfo, 70 LogType, 71 storedFileInfo 72} from './utils'; 73import { 74 projectConfig, 75 sdkConfigs, 76 sdkConfigPrefix, 77 globalProgram 78} from '../main'; 79import { 80 CUSTOM_BUILDER_METHOD, 81 INNER_COMPONENT_NAMES, 82 GLOBAL_CUSTOM_BUILDER_METHOD 83} from './component_map'; 84import { 85 type ResolveModuleInfo, 86 SOURCE_FILES 87} from './ets_checker'; 88import { 89 getRealModulePath, 90 validateModuleSpecifier 91} from './fast_build/system_api/api_check_utils'; 92import processStructComponentV2, { StructInfo } from './process_struct_componentV2'; 93 94const IMPORT_FILE_ASTCACHE: Map<string, ts.SourceFile> = 95 process.env.watchMode === 'true' ? new Map() : (SOURCE_FILES || new Map()); 96 97export default function processImport(node: ts.ImportDeclaration | ts.ImportEqualsDeclaration | 98 ts.ExportDeclaration, pagesDir: string, log: LogInfo[], asName: Map<string, string> = new Map(), 99 isEntryPage: boolean = true, pathCollection: Set<string> = new Set()): void { 100 let filePath: string; 101 let defaultName: string; 102 if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) { 103 filePath = node.moduleSpecifier.getText().replace(/'|"/g, ''); 104 if (ts.isImportDeclaration(node) && node.importClause && node.importClause.name && 105 ts.isIdentifier(node.importClause.name)) { 106 defaultName = node.importClause.name.escapedText.toString(); 107 if (isEntryPage) { 108 asName.set(defaultName, defaultName); 109 } 110 } 111 if (ts.isImportDeclaration(node) && node.importClause && node.importClause.namedBindings && 112 ts.isNamedImports(node.importClause.namedBindings) && 113 node.importClause.namedBindings.elements && isEntryPage) { 114 validateModuleSpecifier(node.moduleSpecifier, log); 115 node.importClause.namedBindings.elements.forEach(item => { 116 if (item.name && ts.isIdentifier(item.name)) { 117 validateModuleName(item.name, log); 118 if (item.propertyName && ts.isIdentifier(item.propertyName) && asName) { 119 asName.set(item.propertyName.escapedText.toString(), item.name.escapedText.toString()); 120 } else { 121 asName.set(item.name.escapedText.toString(), item.name.escapedText.toString()); 122 } 123 } 124 }); 125 } 126 } else { 127 if (node.moduleReference && ts.isExternalModuleReference(node.moduleReference) && 128 node.moduleReference.expression && ts.isStringLiteral(node.moduleReference.expression)) { 129 filePath = node.moduleReference.expression.text; 130 defaultName = node.name.escapedText.toString(); 131 if (isEntryPage) { 132 asName.set(defaultName, defaultName); 133 } 134 } 135 } 136 137 try { 138 const fileResolvePath: string = getFileFullPath(filePath, pagesDir); 139 if (fs.existsSync(fileResolvePath) && fs.statSync(fileResolvePath).isFile() && 140 !pathCollection.has(fileResolvePath)) { 141 let sourceFile: ts.SourceFile; 142 pathCollection.add(fileResolvePath); 143 if (IMPORT_FILE_ASTCACHE.has(fileResolvePath)) { 144 sourceFile = IMPORT_FILE_ASTCACHE.get(fileResolvePath); 145 } else { 146 sourceFile = generateSourceFileAST(fileResolvePath, filePath); 147 IMPORT_FILE_ASTCACHE[fileResolvePath] = sourceFile; 148 } 149 visitAllNode(sourceFile, sourceFile, defaultName, asName, path.dirname(fileResolvePath), log, 150 new Set(), new Set(), new Set(), new Map(), pathCollection, fileResolvePath, /\.d\.ets$/.test(fileResolvePath)); 151 } 152 } catch (e) { 153 // ignore 154 } 155} 156 157function generateSourceFileAST(fileResolvePath: string, filePath: string): ts.SourceFile { 158 const originContent: string = fs.readFileSync(fileResolvePath, { encoding: 'utf-8' }); 159 const content: string = path.extname(fileResolvePath) === EXTNAME_ETS ? 160 preprocessNewExtend(preprocessExtend(processSystemApi(originContent))) : originContent; 161 return ts.createSourceFile(fileResolvePath, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.ETS); 162} 163 164type structDecoratorResult = { 165 hasRecycle: boolean 166}; 167 168const MODIFIER_LENGTH: number = 2; 169 170function visitAllNode(node: ts.Node, sourceFile: ts.SourceFile, defaultNameFromParent: string, 171 asNameFromParent: Map<string, string>, pagesDir: string, log: LogInfo[], entryCollection: Set<string>, 172 exportCollection: Set<string>, defaultCollection: Set<string>, asExportCollection: Map<string, string>, 173 pathCollection: Set<string>, fileResolvePath: string, isDETS: boolean): void { 174 if (isObservedClass(node)) { 175 collectSpecialFunctionNode(node as ts.ClassDeclaration, asNameFromParent, defaultNameFromParent, defaultCollection, 176 asExportCollection, observedClassCollection); 177 // @ts-ignore 178 observedClassCollection.add(node.name.getText()); 179 } 180 if (isCustomDialogClass(node)) { 181 collectSpecialFunctionNode(node as ts.StructDeclaration, asNameFromParent, defaultNameFromParent, defaultCollection, 182 asExportCollection, componentCollection.customDialogs); 183 // @ts-ignore 184 componentCollection.customDialogs.add(node.name.getText()); 185 } 186 if (ts.isEnumDeclaration(node) && node.name) { 187 enumCollection.add(node.name.getText()); 188 } 189 const structDecorator: structDecoratorResult = { hasRecycle: false }; 190 if (ts.isStructDeclaration(node) && ts.isIdentifier(node.name) && isCustomComponent(node, structDecorator)) { 191 addDependencies(node, defaultNameFromParent, asNameFromParent, isDETS, structDecorator); 192 isExportEntry(node, log, entryCollection, exportCollection, defaultCollection, fileResolvePath, sourceFile); 193 if (asExportCollection.has(node.name.getText())) { 194 componentCollection.customComponents.add(asExportCollection.get(node.name.getText())); 195 if (isDETS) { 196 storedFileInfo.getCurrentArkTsFile().compFromDETS.add(asExportCollection.get(node.name.getText())); 197 } 198 if (structDecorator.hasRecycle) { 199 storedFileInfo.getCurrentArkTsFile().recycleComponents.add(asExportCollection.get(node.name.getText())); 200 } 201 } 202 const modifiers: readonly ts.Modifier[] = 203 ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined; 204 if (modifiers && modifiers.length >= MODIFIER_LENGTH && modifiers[0] && 205 modifiers[0].kind === ts.SyntaxKind.ExportKeyword && modifiers[1] && 206 modifiers[1].kind === ts.SyntaxKind.DefaultKeyword) { 207 if (!defaultNameFromParent && hasCollection(node.name)) { 208 addDefaultExport(node, isDETS, structDecorator); 209 } else if (defaultNameFromParent && asNameFromParent.has(defaultNameFromParent)) { 210 componentCollection.customComponents.add(asNameFromParent.get(defaultNameFromParent)); 211 if (isDETS) { 212 storedFileInfo.getCurrentArkTsFile().compFromDETS.add(asNameFromParent.get(defaultNameFromParent)); 213 } 214 if (structDecorator.hasRecycle) { 215 storedFileInfo.getCurrentArkTsFile().recycleComponents.add(asNameFromParent.get(defaultNameFromParent)); 216 } 217 } 218 } 219 if (defaultCollection.has(node.name.getText())) { 220 componentCollection.customComponents.add(CUSTOM_COMPONENT_DEFAULT); 221 if (isDETS) { 222 storedFileInfo.getCurrentArkTsFile().compFromDETS.add(CUSTOM_COMPONENT_DEFAULT); 223 } 224 if (structDecorator.hasRecycle) { 225 storedFileInfo.getCurrentArkTsFile().recycleComponents.add(CUSTOM_COMPONENT_DEFAULT); 226 } 227 } 228 } 229 if (ts.isFunctionDeclaration(node) && hasDecorator(node, COMPONENT_BUILDER_DECORATOR)) { 230 collectSpecialFunctionNode(node, asNameFromParent, defaultNameFromParent, defaultCollection, 231 asExportCollection, CUSTOM_BUILDER_METHOD); 232 collectSpecialFunctionNode(node, asNameFromParent, defaultNameFromParent, defaultCollection, 233 asExportCollection, GLOBAL_CUSTOM_BUILDER_METHOD); 234 } 235 if (ts.isExportAssignment(node) && node.expression && ts.isIdentifier(node.expression) && 236 hasCollection(node.expression)) { 237 if (defaultNameFromParent) { 238 const propertiesName: string = node.expression.escapedText.toString(); 239 setDependencies(defaultNameFromParent, undefined, linkCollection.get(propertiesName), 240 propertyCollection.get(propertiesName), propCollection.get(propertiesName), 241 builderParamObjectCollection.get(propertiesName), stateCollection.get(propertiesName), 242 regularCollection.get(propertiesName), storagePropCollection.get(propertiesName), 243 storageLinkCollection.get(propertiesName), provideCollection.get(propertiesName), 244 consumeCollection.get(propertiesName), objectLinkCollection.get(propertiesName), 245 localStorageLinkCollection.get(propertiesName), localStoragePropCollection.get(propertiesName), 246 builderParamInitialization.get(propertiesName), propInitialization.get(propertiesName), isDETS, 247 structDecorator); 248 } 249 addDefaultExport(node, isDETS, structDecorator); 250 } 251 if (ts.isExportAssignment(node) && node.expression && ts.isIdentifier(node.expression)) { 252 if (defaultNameFromParent) { 253 asNameFromParent.set(node.expression.getText(), asNameFromParent.get(defaultNameFromParent)); 254 } 255 defaultCollection.add(node.expression.getText()); 256 } 257 if (ts.isExportDeclaration(node) && node.exportClause && 258 ts.isNamedExports(node.exportClause) && node.exportClause.elements) { 259 node.exportClause.elements.forEach(item => { 260 if (process.env.watchMode === 'true') { 261 exportCollection.add((item.propertyName ? item.propertyName : item.name).escapedText.toString()); 262 } 263 if (item.name && ts.isIdentifier(item.name)) { 264 if (!item.propertyName) { 265 asExportCollection.set(item.name.escapedText.toString(), item.name.escapedText.toString()); 266 } else if (item.propertyName && ts.isIdentifier(item.propertyName)) { 267 validateModuleName(item.name, log, sourceFile, fileResolvePath); 268 if (hasCollection(item.propertyName)) { 269 let asExportName: string = item.name.escapedText.toString(); 270 const asExportPropertyName: string = item.propertyName.escapedText.toString(); 271 if (asNameFromParent.has(asExportName)) { 272 asExportName = asNameFromParent.get(asExportName); 273 } 274 setDependencies(asExportName, undefined, linkCollection.get(asExportPropertyName), 275 propertyCollection.get(asExportPropertyName), 276 propCollection.get(asExportPropertyName), 277 builderParamObjectCollection.get(asExportPropertyName), 278 stateCollection.get(asExportPropertyName), regularCollection.get(asExportPropertyName), 279 storagePropCollection.get(asExportPropertyName), storageLinkCollection.get(asExportPropertyName), 280 provideCollection.get(asExportPropertyName), consumeCollection.get(asExportPropertyName), 281 objectLinkCollection.get(asExportPropertyName), localStorageLinkCollection.get(asExportPropertyName), 282 localStoragePropCollection.get(asExportPropertyName), builderParamInitialization.get(asExportPropertyName), 283 propInitialization.get(asExportPropertyName), isDETS, structDecorator); 284 } 285 asExportCollection.set(item.propertyName.escapedText.toString(), item.name.escapedText.toString()); 286 } 287 } 288 if (item.name && ts.isIdentifier(item.name) && asNameFromParent.has(item.name.escapedText.toString()) && 289 item.propertyName && ts.isIdentifier(item.propertyName)) { 290 asNameFromParent.set(item.propertyName.escapedText.toString(), 291 asNameFromParent.get(item.name.escapedText.toString())); 292 } 293 }); 294 } 295 if (ts.isExportDeclaration(node) && node.moduleSpecifier && 296 ts.isStringLiteral(node.moduleSpecifier)) { 297 if (process.env.watchMode === 'true' && node.exportClause && ts.isNamedExports(node.exportClause) && 298 node.exportClause.elements) { 299 node.exportClause.elements.forEach(item => { 300 exportCollection.add((item.propertyName ? item.propertyName : item.name).escapedText.toString()); 301 if (item.propertyName && ts.isIdentifier(item.propertyName) && item.name && 302 ts.isIdentifier(item.name) && asNameFromParent.has(item.name.escapedText.toString())) { 303 asNameFromParent.set(item.propertyName.escapedText.toString(), 304 asNameFromParent.get(item.name.escapedText.toString())); 305 defaultCollection.add(item.name.escapedText.toString()); 306 } 307 }); 308 } 309 processImport(node, pagesDir, log, asNameFromParent, true, new Set(pathCollection)); 310 } 311 if (ts.isImportDeclaration(node)) { 312 if (node.importClause && node.importClause.name && ts.isIdentifier(node.importClause.name) && 313 asNameFromParent.has(node.importClause.name.getText())) { 314 processImport(node, pagesDir, log, asNameFromParent, false, new Set(pathCollection)); 315 } else if (node.importClause && node.importClause.namedBindings && 316 ts.isNamedImports(node.importClause.namedBindings) && node.importClause.namedBindings.elements) { 317 let nested: boolean = false; 318 node.importClause.namedBindings.elements.forEach(item => { 319 if (item.name && ts.isIdentifier(item.name) && asNameFromParent.has(item.name.escapedText.toString())) { 320 nested = true; 321 if (item.propertyName && ts.isIdentifier(item.propertyName)) { 322 asNameFromParent.set(item.propertyName.escapedText.toString(), 323 asNameFromParent.get(item.name.escapedText.toString())); 324 } 325 } 326 }); 327 if (nested) { 328 processImport(node, pagesDir, log, asNameFromParent, false, new Set(pathCollection)); 329 } 330 } 331 } 332 node.getChildren().reverse().forEach((item: ts.Node) => visitAllNode(item, sourceFile, 333 defaultNameFromParent, asNameFromParent, pagesDir, log, entryCollection, exportCollection, 334 defaultCollection, asExportCollection, pathCollection, fileResolvePath, isDETS)); 335} 336 337function collectSpecialFunctionNode(node: ts.FunctionDeclaration | ts.ClassDeclaration | ts.StructDeclaration, 338 asNameFromParent: Map<string, string>, defaultNameFromParent: string, defaultCollection: Set<string>, 339 asExportCollection: Map<string, string>, collection: Set<string>): void { 340 const name: string = node.name.getText(); 341 const modifiers: readonly ts.Modifier[] = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined; 342 if (asNameFromParent.has(name)) { 343 collection.add(asNameFromParent.get(name)); 344 } else if (modifiers && modifiers.length >= 1 && modifiers[0] && 345 modifiers[0].kind === ts.SyntaxKind.ExportKeyword) { 346 if (modifiers.length === 1) { 347 collection.add(name); 348 } else if (modifiers.length >= MODIFIER_LENGTH && modifiers[1] && modifiers[1].kind === 349 ts.SyntaxKind.DefaultKeyword) { 350 collection.add(CUSTOM_COMPONENT_DEFAULT); 351 if (defaultNameFromParent && asNameFromParent.has(defaultNameFromParent)) { 352 collection.add(asNameFromParent.get(defaultNameFromParent)); 353 } 354 } 355 } else if (defaultCollection.has(name)) { 356 collection.add(CUSTOM_COMPONENT_DEFAULT); 357 } else if (asExportCollection.has(name)) { 358 collection.add(asExportCollection.get(name)); 359 } 360} 361 362function isExportEntry(node: ts.StructDeclaration, log: LogInfo[], entryCollection: Set<string>, 363 exportCollection: Set<string>, defaultCollection: Set<string>, fileResolvePath: string, 364 sourceFile: ts.SourceFile): void { 365 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node); 366 if (process.env.watchMode === 'true' && node && decorators) { 367 let existExport: boolean = false; 368 let existEntry: boolean = false; 369 const modifiers: readonly ts.Modifier[] = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined; 370 if (modifiers) { 371 for (let i = 0; i < modifiers.length; i++) { 372 if (modifiers[i].kind === ts.SyntaxKind.ExportKeyword) { 373 existExport = true; 374 break; 375 } 376 } 377 } 378 for (let i = 0; i < decorators.length; i++) { 379 if (decorators[i].getText() === COMPONENT_DECORATOR_ENTRY) { 380 entryCollection.add(node.name.escapedText.toString()); 381 existEntry = true; 382 break; 383 } 384 } 385 } 386} 387 388function addDependencies(node: ts.StructDeclaration, defaultNameFromParent: string, 389 asNameFromParent: Map<string, string>, isDETS: boolean, structDecorator: structDecoratorResult): void { 390 const componentName: string = node.name.getText(); 391 const ComponentSet: IComponentSet = getComponentSet(node, false); 392 const modifiers: readonly ts.Modifier[] = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined; 393 if (defaultNameFromParent && modifiers && modifiers.length >= MODIFIER_LENGTH && modifiers[0] && 394 modifiers[1] && modifiers[0].kind === ts.SyntaxKind.ExportKeyword && 395 modifiers[1].kind === ts.SyntaxKind.DefaultKeyword) { 396 setDependencies(defaultNameFromParent, undefined, ComponentSet.links, ComponentSet.properties, 397 ComponentSet.props, ComponentSet.builderParams, ComponentSet.states, ComponentSet.regulars, 398 ComponentSet.storageProps, ComponentSet.storageLinks, ComponentSet.provides, 399 ComponentSet.consumes, ComponentSet.objectLinks, ComponentSet.localStorageLink, 400 ComponentSet.localStorageProp, ComponentSet.builderParamData, ComponentSet.propData, isDETS, 401 structDecorator); 402 } else if (asNameFromParent.has(componentName)) { 403 setDependencies(asNameFromParent.get(componentName), undefined, ComponentSet.links, ComponentSet.properties, 404 ComponentSet.props, ComponentSet.builderParams, ComponentSet.states, ComponentSet.regulars, 405 ComponentSet.storageProps, ComponentSet.storageLinks, ComponentSet.provides, 406 ComponentSet.consumes, ComponentSet.objectLinks, ComponentSet.localStorageLink, 407 ComponentSet.localStorageProp, ComponentSet.builderParamData, ComponentSet.propData, isDETS, 408 structDecorator); 409 } else { 410 setDependencies(componentName, undefined, ComponentSet.links, ComponentSet.properties, ComponentSet.props, 411 ComponentSet.builderParams, ComponentSet.states, ComponentSet.regulars, 412 ComponentSet.storageProps, ComponentSet.storageLinks, ComponentSet.provides, 413 ComponentSet.consumes, ComponentSet.objectLinks, ComponentSet.localStorageLink, 414 ComponentSet.localStorageProp, ComponentSet.builderParamData, ComponentSet.propData, isDETS, 415 structDecorator); 416 } 417} 418 419function addDefaultExport(node: ts.StructDeclaration | ts.ExportAssignment, isDETS: boolean, 420 structDecorator: structDecoratorResult): void { 421 let name: string; 422 if (ts.isStructDeclaration(node) && node.name && ts.isIdentifier(node.name)) { 423 name = node.name.escapedText.toString(); 424 } else if (ts.isExportAssignment(node) && node.expression && ts.isIdentifier(node.expression)) { 425 name = node.expression.escapedText.toString(); 426 } else { 427 return; 428 } 429 setDependencies(CUSTOM_COMPONENT_DEFAULT, undefined, 430 linkCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 431 new Set([...linkCollection.get(CUSTOM_COMPONENT_DEFAULT), ...linkCollection.get(name)]) : 432 linkCollection.get(name), 433 propertyCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 434 new Set([...propertyCollection.get(CUSTOM_COMPONENT_DEFAULT), 435 ...propertyCollection.get(name)]) : propertyCollection.get(name), 436 propCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 437 new Set([...propCollection.get(CUSTOM_COMPONENT_DEFAULT), ...propCollection.get(name)]) : 438 propCollection.get(name), 439 builderParamObjectCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 440 new Set([...builderParamObjectCollection.get(CUSTOM_COMPONENT_DEFAULT), 441 ...builderParamObjectCollection.get(name)]) : builderParamObjectCollection.get(name), 442 stateCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 443 new Set([...stateCollection.get(CUSTOM_COMPONENT_DEFAULT), 444 ...stateCollection.get(name)]) : stateCollection.get(name), 445 regularCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 446 new Set([...regularCollection.get(CUSTOM_COMPONENT_DEFAULT), 447 ...regularCollection.get(name)]) : regularCollection.get(name), 448 storagePropCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 449 new Set([...storagePropCollection.get(CUSTOM_COMPONENT_DEFAULT), 450 ...storagePropCollection.get(name)]) : storagePropCollection.get(name), 451 storageLinkCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 452 new Set([...storageLinkCollection.get(CUSTOM_COMPONENT_DEFAULT), 453 ...storageLinkCollection.get(name)]) : storageLinkCollection.get(name), 454 provideCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 455 new Set([...provideCollection.get(CUSTOM_COMPONENT_DEFAULT), 456 ...provideCollection.get(name)]) : provideCollection.get(name), 457 consumeCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 458 new Set([...consumeCollection.get(CUSTOM_COMPONENT_DEFAULT), 459 ...consumeCollection.get(name)]) : consumeCollection.get(name), 460 objectLinkCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 461 new Set([...objectLinkCollection.get(CUSTOM_COMPONENT_DEFAULT), 462 ...objectLinkCollection.get(name)]) : objectLinkCollection.get(name), 463 getNewLocalStorageMap(localStorageLinkCollection, name), 464 getNewLocalStorageMap(localStoragePropCollection, name), 465 builderParamInitialization.has(CUSTOM_COMPONENT_DEFAULT) ? 466 new Set([...builderParamInitialization.get(CUSTOM_COMPONENT_DEFAULT), 467 ...builderParamInitialization.get(name)]) : builderParamInitialization.get(name), 468 propInitialization.has(CUSTOM_COMPONENT_DEFAULT) ? 469 new Set([...propInitialization.get(CUSTOM_COMPONENT_DEFAULT), 470 ...propInitialization.get(name)]) : propInitialization.get(name), isDETS, 471 structDecorator 472 ); 473} 474 475function getNewLocalStorageMap(collection: Map<string, Map<string, Set<string>>>, name: string) 476 : Map<string, Set<string>> { 477 let localStorageLinkMap: Map<string, Set<string>> = new Map(); 478 if (collection.has(CUSTOM_COMPONENT_DEFAULT)) { 479 const tempSet: Set<string> = new Set(); 480 if (collection.get(CUSTOM_COMPONENT_DEFAULT)) { 481 for (const key of collection.get(CUSTOM_COMPONENT_DEFAULT).keys()) { 482 tempSet.add(key); 483 } 484 } 485 if (collection.get(name)) { 486 for (const key of collection.get(name).keys()) { 487 tempSet.add(key); 488 } 489 } 490 localStorageLinkMap.set(name, tempSet); 491 } else { 492 localStorageLinkMap = collection.get(name); 493 } 494 return localStorageLinkMap; 495} 496 497function setDependencies(component: string, asComponentName: string, linkArray: Set<string>, propertyArray: Set<string>, 498 propArray: Set<string>, builderParamArray: Set<string>, stateArray: Set<string>, 499 regularArray: Set<string>, storagePropsArray: Set<string>, storageLinksArray: Set<string>, 500 providesArray: Set<string>, consumesArray: Set<string>, objectLinksArray: Set<string>, 501 localStorageLinkMap: Map<string, Set<string>>, localStoragePropMap: Map<string, Set<string>>, 502 builderParamData: Set<string>, propData: Set<string>, isDETS: boolean, 503 structDecorator: structDecoratorResult): void { 504 if (asComponentName) { 505 linkCollection.set(asComponentName, linkArray); 506 storedFileInfo.overallLinkCollection.set(asComponentName, linkArray); 507 } else if (!asComponentName && component) { 508 linkCollection.set(component, linkArray); 509 if (projectConfig.compileMode === 'esmodule' && process.env.compileTool === 'rollup') { 510 storedFileInfo.overallLinkCollection.set(component, linkArray); 511 } 512 } 513 propertyCollection.set(component, propertyArray); 514 if (!propCollection.get(component)) { 515 propCollection.set(component, propArray); 516 } 517 if (asComponentName) { 518 storedFileInfo.overallBuilderParamCollection.set(asComponentName, builderParamArray); 519 } else if (!asComponentName && component && projectConfig.compileMode === 'esmodule' && 520 process.env.compileTool === 'rollup') { 521 storedFileInfo.overallBuilderParamCollection.set(component, builderParamArray); 522 } 523 builderParamObjectCollection.set(component, builderParamArray); 524 componentCollection.customComponents.add(component); 525 if (isDETS) { 526 storedFileInfo.getCurrentArkTsFile().compFromDETS.add(component); 527 } 528 if (structDecorator.hasRecycle) { 529 storedFileInfo.getCurrentArkTsFile().recycleComponents.add(component); 530 } 531 stateCollection.set(component, stateArray); 532 regularCollection.set(component, regularArray); 533 storagePropCollection.set(component, storagePropsArray); 534 storageLinkCollection.set(component, storageLinksArray); 535 provideCollection.set(component, providesArray); 536 consumeCollection.set(component, consumesArray); 537 if (asComponentName) { 538 storedFileInfo.overallObjectLinkCollection.set(asComponentName, objectLinksArray); 539 } else if (!asComponentName && component && projectConfig.compileMode === 'esmodule' && 540 process.env.compileTool === 'rollup') { 541 storedFileInfo.overallObjectLinkCollection.set(component, objectLinksArray); 542 } 543 objectLinkCollection.set(component, objectLinksArray); 544 localStorageLinkCollection.set(component, localStorageLinkMap); 545 localStoragePropCollection.set(component, localStoragePropMap); 546 if (!builderParamInitialization.get(component)) { 547 builderParamInitialization.set(component, builderParamData); 548 } 549 if (!propInitialization.get(component)) { 550 propInitialization.set(component, propData); 551 } 552} 553 554function hasCollection(node: ts.Identifier): boolean { 555 const name: string = node.escapedText.toString(); 556 return linkCollection.has(name) || 557 propCollection.has(name) || 558 propertyCollection.has(name) || 559 builderParamObjectCollection.has(name) || 560 stateCollection.has(name) || 561 regularCollection.has(name) || 562 storagePropCollection.has(name) || 563 storageLinkCollection.has(name) || 564 provideCollection.has(name) || 565 consumeCollection.has(name) || 566 objectLinkCollection.has(name) || 567 localStorageLinkCollection.has(name) || 568 localStoragePropCollection.has(name); 569} 570 571function isModule(filePath: string): boolean { 572 return !/^(\.|\.\.)?\//.test(filePath) || filePath.indexOf(projectConfig.packageDir) > -1; 573} 574 575function isCustomComponent(node: ts.StructDeclaration, structDecorator: structDecoratorResult): boolean { 576 let isComponent: boolean = false; 577 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node); 578 if (decorators && decorators.length) { 579 for (let i = 0; i < decorators.length; ++i) { 580 const decoratorName: ts.Expression = decorators[i].expression; 581 if (ts.isIdentifier(decoratorName) || ts.isCallExpression(decoratorName)) { 582 let name: string = ''; 583 if (ts.isCallExpression(decoratorName) && ts.isIdentifier(decoratorName.expression)) { 584 name = decoratorName.expression.escapedText.toString(); 585 } else if (ts.isIdentifier(decoratorName)) { 586 name = decoratorName.escapedText.toString(); 587 } 588 if (CUSTOM_DECORATOR_NAME.has(name)) { 589 isComponent = true; 590 } 591 if (name === DECORATOR_REUSEABLE) { 592 structDecorator.hasRecycle = true; 593 } 594 } 595 } 596 } 597 return isComponent; 598} 599 600let packageJsonEntry: string = ''; 601 602function isPackageJsonEntry(filePath: string): boolean { 603 const packageJsonPath: string = path.join(filePath, projectConfig.packageJson); 604 if (fs.existsSync(packageJsonPath)) { 605 let entryTypes: string; 606 let entryMain: string; 607 try { 608 const packageJson: Object = 609 (projectConfig.packageManagerType === 'npm' ? JSON : JSON5).parse(fs.readFileSync(packageJsonPath).toString()); 610 entryTypes = packageJson.types; 611 entryMain = packageJson.main; 612 } catch (e) { 613 return false; 614 } 615 if (entryExist(filePath, entryTypes)) { 616 packageJsonEntry = path.resolve(filePath, entryTypes); 617 return true; 618 } else if (entryExist(filePath, entryMain)) { 619 packageJsonEntry = path.resolve(filePath, entryMain); 620 return true; 621 } 622 } 623 return false; 624} 625 626function entryExist(filePath: string, entry: string): boolean { 627 return typeof entry === 'string' && fs.existsSync(path.resolve(filePath, entry)) && 628 fs.statSync(path.resolve(filePath, entry)).isFile(); 629} 630 631function getModuleFilePath(filePath: string): string { 632 if (filePath && path.extname(filePath) !== EXTNAME_ETS && isModule(filePath)) { 633 filePath += EXTNAME_ETS; 634 } 635 return filePath; 636} 637 638function getFileResolvePath(fileResolvePath: string, pagesDir: string, filePath: string, 639 projectPath: string): string { 640 const moduleFilePath: string = getModuleFilePath(filePath); 641 const defaultModule: string = path.join(projectPath, moduleFilePath); 642 if (fs.existsSync(defaultModule)) { 643 return defaultModule; 644 } 645 let entryModule: string; 646 let etsModule: string; 647 if (new RegExp(`^@(${sdkConfigPrefix})\\.`).test(filePath.trim())) { 648 for (let i = 0; i < sdkConfigs.length; i++) { 649 const resolveModuleInfo: ResolveModuleInfo = getRealModulePath(sdkConfigs[i].apiPath, filePath, ['.d.ts', '.d.ets']); 650 const systemModule: string = resolveModuleInfo.modulePath; 651 if (fs.existsSync(systemModule)) { 652 return systemModule; 653 } 654 } 655 } 656 if (!projectConfig.aceModuleJsonPath) { 657 entryModule = path.join(projectPath, '../../../../../', moduleFilePath); 658 etsModule = path.join(projectPath, '../../', moduleFilePath); 659 } else { 660 entryModule = path.join(projectPath, '../../../../', moduleFilePath); 661 etsModule = path.join(projectPath, '../', moduleFilePath); 662 } 663 if (fs.existsSync(entryModule)) { 664 return entryModule; 665 } 666 if (fs.existsSync(etsModule)) { 667 return etsModule; 668 } 669 let curPageDir: string = pagesDir; 670 while (!fs.existsSync(fileResolvePath)) { 671 if (filePath.indexOf(projectConfig.packageDir) > -1 && /^(\.|\.\.)\//.test(filePath)) { 672 fileResolvePath = path.join(curPageDir, filePath); 673 } else { 674 fileResolvePath = path.join(curPageDir, projectConfig.packageDir, filePath); 675 } 676 if (fs.existsSync(fileResolvePath + EXTNAME_ETS)) { 677 fileResolvePath = fileResolvePath + EXTNAME_ETS; 678 } else if (isPackageJsonEntry(fileResolvePath)) { 679 fileResolvePath = packageJsonEntry; 680 if (fs.statSync(fileResolvePath).isDirectory()) { 681 if (fs.existsSync(path.join(fileResolvePath, INDEX_ETS))) { 682 fileResolvePath = path.join(fileResolvePath, INDEX_ETS); 683 } else if (fs.existsSync(path.join(fileResolvePath, INDEX_TS))) { 684 fileResolvePath = path.join(fileResolvePath, INDEX_TS); 685 } 686 } 687 } else if (fs.existsSync(path.join(fileResolvePath, INDEX_ETS))) { 688 fileResolvePath = path.join(fileResolvePath, INDEX_ETS); 689 } else if (fs.existsSync(path.join(fileResolvePath, INDEX_TS))) { 690 fileResolvePath = path.join(fileResolvePath, INDEX_TS); 691 } 692 if (curPageDir === path.parse(curPageDir).root) { 693 break; 694 } 695 curPageDir = path.dirname(curPageDir); 696 } 697 return fileResolvePath; 698} 699 700function getFileFullPath(filePath: string, pagesDir: string): string { 701 if (filePath && path.extname(filePath) !== EXTNAME_ETS && path.extname(filePath) !== EXTNAME_TS && 702 !isModule(filePath)) { 703 const dirIndexEtsPath: string = path.resolve(path.resolve(pagesDir, filePath), INDEX_ETS); 704 const dirIndexTsPath: string = path.resolve(path.resolve(pagesDir, filePath), INDEX_TS); 705 if (/^(\.|\.\.)\//.test(filePath) && !fs.existsSync(path.resolve(pagesDir, filePath + EXTNAME_ETS)) && 706 fs.existsSync(dirIndexEtsPath)) { 707 filePath = dirIndexEtsPath; 708 } else if (/^(\.|\.\.)\//.test(filePath) && !fs.existsSync(path.resolve(pagesDir, filePath + EXTNAME_TS)) && 709 fs.existsSync(dirIndexTsPath)) { 710 filePath = dirIndexTsPath; 711 } else { 712 filePath += getExtensionIfUnfullySpecifiedFilepath(path.resolve(pagesDir, filePath)); 713 } 714 } 715 716 let fileResolvePath: string; 717 if (/^(\.|\.\.)\//.test(filePath) && filePath.indexOf(projectConfig.packageDir) < 0) { 718 fileResolvePath = path.resolve(pagesDir, filePath); 719 } else if (/^\//.test(filePath) && filePath.indexOf(projectConfig.packageDir) < 0 || 720 fs.existsSync(filePath) && fs.statSync(filePath).isFile()) { 721 fileResolvePath = filePath; 722 } else { 723 fileResolvePath = getFileResolvePath(fileResolvePath, pagesDir, filePath, projectConfig.projectPath); 724 } 725 726 return fileResolvePath; 727} 728 729function validateModuleName(moduleNode: ts.Identifier, log: LogInfo[], sourceFile?: ts.SourceFile, 730 fileResolvePath?: string): void { 731 const moduleName: string = moduleNode.escapedText.toString(); 732 if (INNER_COMPONENT_NAMES.has(moduleName)) { 733 const error: LogInfo = { 734 type: LogType.ERROR, 735 message: `The module name '${moduleName}' can not be the same as the inner component name.`, 736 pos: moduleNode.getStart(), 737 code: '10905235' 738 }; 739 if (sourceFile && fileResolvePath) { 740 const posOfNode: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(moduleNode.getStart()); 741 const line: number = posOfNode.line + 1; 742 const column: number = posOfNode.character + 1; 743 Object.assign(error, { 744 fileName: fileResolvePath, 745 line: line, 746 column: column 747 }); 748 } 749 log.push(error); 750 } 751} 752 753interface PageInfo { 754 pageFile: string; 755 setChildOnce: boolean; 756} 757 758export function processImportModule(node: ts.ImportDeclaration, pageFile: string, log: LogInfo[], 759 share: object = null): void { 760 let importSymbol: ts.Symbol; 761 let realSymbol: ts.Symbol; 762 let originNode: ts.Node; 763 const pageInfo: PageInfo = { pageFile: pageFile, setChildOnce: false }; 764 validateModuleSpecifier(node.moduleSpecifier, log); 765 766 // import xxx from 'xxx' 767 if (node.importClause && node.importClause.name && ts.isIdentifier(node.importClause.name)) { 768 getDefinedNode(importSymbol, realSymbol, originNode, node.importClause.name, pageInfo, share); 769 } 770 771 // import {xxx} from 'xxx' 772 if (node.importClause && node.importClause.namedBindings && 773 ts.isNamedImports(node.importClause.namedBindings) && 774 node.importClause.namedBindings.elements) { 775 node.importClause.namedBindings.elements.forEach((importSpecifier: ts.ImportSpecifier) => { 776 if (ts.isImportSpecifier(importSpecifier) && importSpecifier.name && ts.isIdentifier(importSpecifier.name)) { 777 getDefinedNode(importSymbol, realSymbol, originNode, importSpecifier.name, pageInfo, share); 778 } 779 }); 780 } 781 782 // import * as xxx from 'xxx' 783 if (node.importClause && node.importClause.namedBindings && 784 ts.isNamespaceImport(node.importClause.namedBindings) && node.importClause.namedBindings.name && 785 ts.isIdentifier(node.importClause.namedBindings.name)) { 786 storedFileInfo.isAsPageImport = true; 787 getDefinedNode(importSymbol, realSymbol, originNode, node.importClause.namedBindings.name, pageInfo, share); 788 } 789} 790 791function getDefinedNode(importSymbol: ts.Symbol, realSymbol: ts.Symbol, originNode: ts.Node, 792 usedNode: ts.Identifier, pageInfo: PageInfo, share: object = null): void { 793 const checker: ts.TypeChecker | undefined = CurrentProcessFile.getChecker(); 794 importSymbol = checker?.getSymbolAtLocation(usedNode); 795 if (importSymbol) { 796 realSymbol = checker?.getAliasedSymbol(importSymbol); 797 } else { 798 realSymbol = null; 799 } 800 if (realSymbol && realSymbol.declarations) { 801 originNode = realSymbol.declarations[0]; 802 } else { 803 originNode = null; 804 } 805 if (originNode) { 806 if (ts.isSourceFile(originNode) && realSymbol.escapedName) { 807 const escapedName: string = realSymbol.escapedName.toString().replace(/^("|')/, '').replace(/("|')$/, ''); 808 if (fs.existsSync(escapedName + '.ets') || fs.existsSync(escapedName + '.ts') && 809 realSymbol.exports && realSymbol.exports instanceof Map) { 810 getIntegrationNodeInfo(originNode, usedNode, realSymbol.exports, pageInfo, share); 811 return; 812 } 813 } 814 processImportNode(originNode, usedNode, false, null, pageInfo, share); 815 } 816} 817 818function getIntegrationNodeInfo(originNode: ts.Node, usedNode: ts.Identifier, exportsMap: ts.SymbolTable, 819 pageInfo: PageInfo, share: object = null): void { 820 for (const usedSymbol of exportsMap) { 821 try { 822 originNode = CurrentProcessFile.getChecker()?.getAliasedSymbol(usedSymbol[1]).declarations[0]; 823 } catch (e) { 824 if (usedSymbol[1] && usedSymbol[1].declarations) { 825 for (let i = 0; i < usedSymbol[1].declarations.length; i++) { 826 originNode = usedSymbol[1].declarations[i]; 827 exportAllManage(originNode, usedNode, pageInfo, share); 828 } 829 } 830 } 831 processImportNode(originNode, usedNode, true, usedSymbol[0], pageInfo, share); 832 } 833} 834 835// export * from 'xxx'; 836function exportAllManage(originNode: ts.Node, usedNode: ts.Identifier, pageInfo: PageInfo, share: object = null): void { 837 let exportOriginNode: ts.Node; 838 if (!originNode.exportClause && originNode.moduleSpecifier && ts.isStringLiteral(originNode.moduleSpecifier)) { 839 const checker: ts.TypeChecker | undefined = CurrentProcessFile.getChecker(); 840 const exportSymbol: ts.Symbol = checker?.getSymbolAtLocation(originNode.moduleSpecifier); 841 if (exportSymbol && exportSymbol.declarations) { 842 exportOriginNode = exportSymbol.declarations[0]; 843 } else { 844 exportOriginNode = null; 845 } 846 if (exportOriginNode) { 847 if (ts.isSourceFile(exportOriginNode) && exportSymbol.escapedName) { 848 const escapedName: string = exportSymbol.escapedName.toString().replace(/^("|')/, '').replace(/("|')$/, ''); 849 if (fs.existsSync(escapedName + '.ets') || fs.existsSync(escapedName + '.ts') && 850 exportSymbol.exports && exportSymbol.exports instanceof Map) { 851 getIntegrationNodeInfo(originNode, usedNode, exportSymbol.exports, pageInfo, share); 852 return; 853 } 854 } 855 } 856 } 857} 858 859function processImportNode(originNode: ts.Node, usedNode: ts.Identifier, importIntegration: boolean, 860 usedPropName: string, pageInfo: PageInfo, share: object = null): void { 861 const structDecorator: structDecoratorResult = { hasRecycle: false }; 862 let name: string; 863 let asComponentName: string; 864 if (importIntegration) { 865 if (storedFileInfo.isAsPageImport) { 866 asComponentName = usedNode.escapedText.toString() + '.' + usedPropName; 867 } 868 name = usedPropName; 869 } else { 870 name = usedNode.escapedText.toString(); 871 } 872 let needCollection: boolean = true; 873 const originFile: string = originNode.getSourceFile() ? originNode.getSourceFile().fileName : undefined; 874 if (ts.isStructDeclaration(originNode) && ts.isIdentifier(originNode.name)) { 875 parseComponentInImportNode(originNode, name, asComponentName, structDecorator, originFile); 876 } else if (isObservedClass(originNode)) { 877 observedClassCollection.add(name); 878 } else if (ts.isFunctionDeclaration(originNode) && hasDecorator(originNode, COMPONENT_BUILDER_DECORATOR)) { 879 CUSTOM_BUILDER_METHOD.add(name); 880 GLOBAL_CUSTOM_BUILDER_METHOD.add(name); 881 } else if (ts.isEnumDeclaration(originNode) && originNode.name) { 882 enumCollection.add(name); 883 } else { 884 needCollection = false; 885 } 886 if (needCollection && pageInfo.pageFile && !pageInfo.setChildOnce && originFile) { 887 const childFile: string = path.resolve(getRealPath(originFile) || originFile); 888 const fileHash = share?.getHashByFilePath ? share.getHashByFilePath(childFile) : ''; 889 storedFileInfo.transformCacheFiles[pageInfo.pageFile].children.push({ 890 fileName: childFile, 891 mtimeMs: fs.existsSync(childFile) ? fs.statSync(childFile).mtimeMs : 0, 892 hash: fileHash 893 }); 894 pageInfo.setChildOnce = true; 895 } 896} 897 898function getRealPath(filePath: string): string { 899 try { 900 const newPath: string = fs.realpathSync.native(filePath); 901 return newPath; 902 } catch (err) { 903 return undefined; 904 } 905} 906 907function setComponentCollectionInfo(name: string, componentSet: IComponentSet, isDETS: boolean, 908 structDecorator: structDecoratorResult, asComponentName: string): void { 909 setDependencies(name, asComponentName, componentSet.links, componentSet.properties, 910 componentSet.props, componentSet.builderParams, componentSet.states, componentSet.regulars, 911 componentSet.storageProps, componentSet.storageLinks, componentSet.provides, 912 componentSet.consumes, componentSet.objectLinks, componentSet.localStorageLink, 913 componentSet.localStorageProp, componentSet.builderParamData, componentSet.propData, isDETS, 914 structDecorator); 915 regularInitialization.set(name, componentSet.regularInit); 916 stateInitialization.set(name, componentSet.stateInit); 917 provideInitialization.set(name, componentSet.provideInit); 918 privateCollection.set(name, componentSet.privateCollection); 919 regularStaticCollection.set(name, componentSet.regularStaticCollection); 920 if (asComponentName) { 921 const asComponentNameStructInfo: StructInfo = 922 processStructComponentV2.getOrCreateStructInfo(asComponentName); 923 asComponentNameStructInfo.updatePropsDecoratorsV1.push( 924 ...componentSet.states, ...componentSet.props, 925 ...componentSet.provides, ...componentSet.objectLinks 926 ); 927 asComponentNameStructInfo.linkDecoratorsV1.push(...componentSet.links); 928 return; 929 } 930 const nameStructInfo: StructInfo = processStructComponentV2.getOrCreateStructInfo(name); 931 nameStructInfo.updatePropsDecoratorsV1.push( 932 ...componentSet.states, ...componentSet.props, 933 ...componentSet.provides, ...componentSet.objectLinks 934 ); 935 nameStructInfo.linkDecoratorsV1.push(...componentSet.links); 936} 937 938function parseComponentInImportNode(originNode: ts.StructDeclaration, name: string, 939 asComponentName: string, structDecorator: structDecoratorResult, originFile: string): void { 940 componentCollection.customComponents.add(name); 941 const structInfo: StructInfo = asComponentName ? 942 processStructComponentV2.getOrCreateStructInfo(asComponentName) : 943 processStructComponentV2.getOrCreateStructInfo(name); 944 if (isComponentV2(originNode)) { 945 parseComponentV2InImportNode(originNode, name, originFile, structInfo); 946 return; 947 } 948 if (isCustomDialogClass(originNode)) { 949 structInfo.isCustomDialog = true; 950 componentCollection.customDialogs.add(name); 951 } 952 if (isCustomComponent(originNode, structDecorator)) { 953 structInfo.isComponentV1 = true; 954 let isDETS: boolean = false; 955 const componentSet: IComponentSet = getComponentSet(originNode, false); 956 while (originNode) { 957 if (ts.isSourceFile(originNode) && /\.d\.ets$/.test(originNode.fileName)) { 958 isDETS = true; 959 } 960 originNode = originNode.parent; 961 } 962 setComponentCollectionInfo(name, componentSet, isDETS, structDecorator, asComponentName); 963 } 964} 965 966function parseComponentV2InImportNode(node: ts.StructDeclaration, name: string, originFile: string, 967 structInfo: StructInfo): void { 968 structInfo.isComponentV2 = true; 969 const isDETS: boolean = originFile && /\.d\.ets$/.test(originFile); 970 if (isDETS) { 971 storedFileInfo.getCurrentArkTsFile().compFromDETS.add(name); 972 } 973 if (isReusableV2(node)) { 974 storedFileInfo.getCurrentArkTsFile().reuseComponentsV2.add(name); 975 } 976 processStructComponentV2.parseComponentProperty(node, structInfo, null, null); 977} 978 979function isComponentV2(node: ts.StructDeclaration): boolean { 980 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node); 981 return decorators.some((item: ts.Decorator) => { 982 const name: string = item.getText().replace(/\([^\(\)]*\)/, '').replace('@', '').trim(); 983 return name === 'ComponentV2'; 984 }); 985} 986 987function isReusableV2(node: ts.StructDeclaration): boolean { 988 const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node); 989 return decorators.some((item: ts.Decorator) => { 990 const name: string = item.getText().replace(/\([^\(\)]*\)/, '').replace('@', '').trim(); 991 return name === DECORATOR_REUSABLE_V2; 992 }); 993} 994