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