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