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