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 NODE_MODULES, 25 INDEX_ETS, 26 INDEX_TS, 27 PACKAGE_JSON, 28 STRUCT, 29 CLASS, 30 CUSTOM_COMPONENT_DEFAULT, 31 CUSTOM_DECORATOR_NAME, 32 COMPONENT_DECORATOR_ENTRY, 33 COMPONENT_BUILDER_DECORATOR, 34 CARD_LOG_TYPE_IMPORT 35} from './pre_define'; 36import { 37 propertyCollection, 38 linkCollection, 39 componentCollection, 40 preprocessExtend, 41 preprocessNewExtend, 42 processSystemApi, 43 propCollection, 44 isObservedClass, 45 isCustomDialogClass, 46 observedClassCollection, 47 enumCollection, 48 getComponentSet, 49 IComponentSet, 50 builderParamObjectCollection, 51 stateCollection, 52 regularCollection, 53 storagePropCollection, 54 storageLinkCollection, 55 provideCollection, 56 consumeCollection, 57 objectLinkCollection, 58 localStorageLinkCollection, 59 localStoragePropCollection, 60 builderParamInitialization 61} from './validate_ui_syntax'; 62import { 63 getExtensionIfUnfullySpecifiedFilepath, 64 hasDecorator, 65 LogInfo, 66 LogType, 67 repeatLog 68} from './utils'; 69import { projectConfig } from '../main'; 70import { 71 CUSTOM_BUILDER_METHOD, 72 INNER_COMPONENT_NAMES, 73 GLOBAL_CUSTOM_BUILDER_METHOD 74} from './component_map'; 75import { validatorCard } from './process_ui_syntax'; 76 77export const IMPORT_FILE_ASTCACHE: Map<string, ts.SourceFile> = new Map(); 78 79export default function processImport(node: ts.ImportDeclaration | ts.ImportEqualsDeclaration | 80 ts.ExportDeclaration, pagesDir: string, log: LogInfo[], asName: Map<string, string> = new Map(), 81isEntryPage: boolean = true, pathCollection: Set<string> = new Set()): void { 82 let filePath: string; 83 let defaultName: string; 84 if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) { 85 filePath = node.moduleSpecifier.getText().replace(/'|"/g, ''); 86 if (ts.isImportDeclaration(node) && node.importClause && node.importClause.name && 87 ts.isIdentifier(node.importClause.name)) { 88 defaultName = node.importClause.name.escapedText.toString(); 89 if (isEntryPage) { 90 asName.set(defaultName, defaultName); 91 } 92 } 93 if (ts.isImportDeclaration(node) && node.importClause && node.importClause.namedBindings && 94 ts.isNamedImports(node.importClause.namedBindings) && 95 node.importClause.namedBindings.elements && isEntryPage) { 96 node.importClause.namedBindings.elements.forEach(item => { 97 if (item.name && ts.isIdentifier(item.name)) { 98 validateModuleName(item.name, log); 99 if (item.propertyName && ts.isIdentifier(item.propertyName) && asName) { 100 asName.set(item.propertyName.escapedText.toString(), item.name.escapedText.toString()); 101 } else { 102 asName.set(item.name.escapedText.toString(), item.name.escapedText.toString()); 103 } 104 } 105 }); 106 } 107 } else { 108 if (node.moduleReference && ts.isExternalModuleReference(node.moduleReference) && 109 node.moduleReference.expression && ts.isStringLiteral(node.moduleReference.expression)) { 110 filePath = node.moduleReference.expression.text; 111 defaultName = node.name.escapedText.toString(); 112 if (isEntryPage) { 113 asName.set(defaultName, defaultName); 114 } 115 } 116 } 117 118 if (filePath) { 119 validatorCard(log, CARD_LOG_TYPE_IMPORT, node.getStart()); 120 } 121 122 try { 123 let fileResolvePath: string = getFileFullPath(filePath, pagesDir); 124 if (fs.existsSync(fileResolvePath) && fs.statSync(fileResolvePath).isFile() && 125 !pathCollection.has(fileResolvePath)) { 126 let sourceFile: ts.SourceFile; 127 pathCollection.add(fileResolvePath); 128 if (IMPORT_FILE_ASTCACHE.has(fileResolvePath)) { 129 sourceFile = IMPORT_FILE_ASTCACHE.get(fileResolvePath); 130 } else { 131 sourceFile = generateSourceFileAST(fileResolvePath, filePath); 132 IMPORT_FILE_ASTCACHE[fileResolvePath] = sourceFile; 133 } 134 visitAllNode(sourceFile, sourceFile, defaultName, asName, path.dirname(fileResolvePath), log, 135 new Set(), new Set(), new Set(), new Map(), pathCollection, fileResolvePath); 136 } 137 } catch (e) { 138 // ignore 139 } 140} 141 142export function generateSourceFileAST(fileResolvePath: string, filePath: string): ts.SourceFile { 143 const originContent: string = fs.readFileSync(fileResolvePath, { encoding: 'utf-8' }); 144 const content: string = path.extname(fileResolvePath) === EXTNAME_ETS ? 145 preprocessNewExtend(preprocessExtend(processSystemApi(originContent.replace( 146 new RegExp('\\b' + STRUCT + '\\b.+\\{', 'g'), item => { 147 return item.replace(new RegExp('\\b' + STRUCT + '\\b', 'g'), `${CLASS} `); 148 })))) : originContent; 149 return ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS); 150} 151 152function visitAllNode(node: ts.Node, sourceFile: ts.SourceFile, defaultNameFromParent: string, 153 asNameFromParent: Map<string, string>, pagesDir: string, log: LogInfo[], entryCollection: Set<string>, 154 exportCollection: Set<string>, defaultCollection: Set<string>, asExportCollection: Map<string, string>, 155 pathCollection: Set<string>, fileResolvePath: string) { 156 if (isObservedClass(node)) { 157 collectSpecialFunctionNode(node as ts.ClassDeclaration, asNameFromParent, defaultNameFromParent, defaultCollection, 158 asExportCollection, observedClassCollection); 159 // @ts-ignore 160 observedClassCollection.add(node.name.getText()); 161 } 162 if (isCustomDialogClass(node)) { 163 collectSpecialFunctionNode(node as ts.StructDeclaration, asNameFromParent, defaultNameFromParent, defaultCollection, 164 asExportCollection, componentCollection.customDialogs); 165 // @ts-ignore 166 componentCollection.customDialogs.add(node.name.getText()); 167 } 168 if (ts.isEnumDeclaration(node) && node.name) { 169 enumCollection.add(node.name.getText()); 170 } 171 if ((ts.isClassDeclaration(node) || ts.isStructDeclaration(node)) && ts.isIdentifier(node.name) && 172 isCustomComponent(node)) { 173 addDependencies(node, defaultNameFromParent, asNameFromParent); 174 isExportEntry(node, log, entryCollection, exportCollection, defaultCollection, fileResolvePath, sourceFile); 175 if (asExportCollection.has(node.name.getText())) { 176 componentCollection.customComponents.add(asExportCollection.get(node.name.getText())); 177 } 178 if (node.modifiers && node.modifiers.length >= 2 && node.modifiers[0] && 179 node.modifiers[0].kind === ts.SyntaxKind.ExportKeyword && node.modifiers[1] && 180 node.modifiers[1].kind === ts.SyntaxKind.DefaultKeyword) { 181 if (!defaultNameFromParent && hasCollection(node.name)) { 182 addDefaultExport(node); 183 } else if (defaultNameFromParent && asNameFromParent.has(defaultNameFromParent)) { 184 componentCollection.customComponents.add(asNameFromParent.get(defaultNameFromParent)); 185 } 186 } 187 if (defaultCollection.has(node.name.getText())) { 188 componentCollection.customComponents.add(CUSTOM_COMPONENT_DEFAULT); 189 } 190 } 191 if (ts.isFunctionDeclaration(node) && hasDecorator(node, COMPONENT_BUILDER_DECORATOR)) { 192 collectSpecialFunctionNode(node, asNameFromParent, defaultNameFromParent, defaultCollection, 193 asExportCollection, CUSTOM_BUILDER_METHOD); 194 collectSpecialFunctionNode(node, asNameFromParent, defaultNameFromParent, defaultCollection, 195 asExportCollection, GLOBAL_CUSTOM_BUILDER_METHOD); 196 } 197 if (ts.isExportAssignment(node) && node.expression && ts.isIdentifier(node.expression) && 198 hasCollection(node.expression)) { 199 if (defaultNameFromParent) { 200 const propertiesName: string = node.expression.escapedText.toString(); 201 setDependencies(defaultNameFromParent, linkCollection.get(propertiesName), 202 propertyCollection.get(propertiesName), propCollection.get(propertiesName), 203 builderParamObjectCollection.get(propertiesName), stateCollection.get(propertiesName), 204 regularCollection.get(propertiesName), storagePropCollection.get(propertiesName), 205 storageLinkCollection.get(propertiesName), provideCollection.get(propertiesName), 206 consumeCollection.get(propertiesName), objectLinkCollection.get(propertiesName), 207 localStorageLinkCollection.get(propertiesName), localStoragePropCollection.get(propertiesName), 208 builderParamInitialization.get(propertiesName)); 209 } 210 addDefaultExport(node); 211 } 212 if (ts.isExportAssignment(node) && node.expression && ts.isIdentifier(node.expression)) { 213 if (defaultNameFromParent) { 214 asNameFromParent.set(node.expression.getText(), asNameFromParent.get(defaultNameFromParent)); 215 } 216 defaultCollection.add(node.expression.getText()); 217 } 218 if (ts.isExportDeclaration(node) && node.exportClause && 219 ts.isNamedExports(node.exportClause) && node.exportClause.elements) { 220 node.exportClause.elements.forEach(item => { 221 if (process.env.watchMode === 'true') { 222 exportCollection.add((item.propertyName ? item.propertyName : item.name).escapedText.toString()); 223 } 224 if (item.name && ts.isIdentifier(item.name)) { 225 if (!item.propertyName) { 226 asExportCollection.set(item.name.escapedText.toString(), item.name.escapedText.toString()); 227 } else if (item.propertyName && ts.isIdentifier(item.propertyName)) { 228 validateModuleName(item.name, log, sourceFile, fileResolvePath); 229 if (hasCollection(item.propertyName)) { 230 let asExportName: string = item.name.escapedText.toString(); 231 const asExportPropertyName: string = item.propertyName.escapedText.toString(); 232 if (asNameFromParent.has(asExportName)) { 233 asExportName = asNameFromParent.get(asExportName); 234 } 235 setDependencies(asExportName, linkCollection.get(asExportPropertyName), 236 propertyCollection.get(asExportPropertyName), 237 propCollection.get(asExportPropertyName), 238 builderParamObjectCollection.get(asExportPropertyName), 239 stateCollection.get(asExportPropertyName), regularCollection.get(asExportPropertyName), 240 storagePropCollection.get(asExportPropertyName), storageLinkCollection.get(asExportPropertyName), 241 provideCollection.get(asExportPropertyName), consumeCollection.get(asExportPropertyName), 242 objectLinkCollection.get(asExportPropertyName), localStorageLinkCollection.get(asExportPropertyName), 243 localStoragePropCollection.get(asExportPropertyName), builderParamInitialization.get(asExportPropertyName)); 244 } 245 asExportCollection.set(item.propertyName.escapedText.toString(), item.name.escapedText.toString()); 246 } 247 } 248 if (item.name && ts.isIdentifier(item.name) && asNameFromParent.has(item.name.escapedText.toString()) && 249 item.propertyName && ts.isIdentifier(item.propertyName)) { 250 asNameFromParent.set(item.propertyName.escapedText.toString(), 251 asNameFromParent.get(item.name.escapedText.toString())); 252 } 253 }); 254 } 255 if (ts.isExportDeclaration(node) && node.moduleSpecifier && 256 ts.isStringLiteral(node.moduleSpecifier)) { 257 if (process.env.watchMode === 'true' && node.exportClause && ts.isNamedExports(node.exportClause) && 258 node.exportClause.elements) { 259 node.exportClause.elements.forEach(item => { 260 exportCollection.add((item.propertyName ? item.propertyName : item.name).escapedText.toString()); 261 if (item.propertyName && ts.isIdentifier(item.propertyName) && item.name && 262 ts.isIdentifier(item.name) && asNameFromParent.has(item.name.escapedText.toString())) { 263 asNameFromParent.set(item.propertyName.escapedText.toString(), 264 asNameFromParent.get(item.name.escapedText.toString())); 265 defaultCollection.add(item.name.escapedText.toString()); 266 } 267 }); 268 } 269 processImport(node, pagesDir, log, asNameFromParent, true, new Set(pathCollection)); 270 } 271 if (ts.isImportDeclaration(node)) { 272 if (node.importClause && node.importClause.name && ts.isIdentifier(node.importClause.name) && 273 asNameFromParent.has(node.importClause.name.getText())) { 274 processImport(node, pagesDir, log, asNameFromParent, false, new Set(pathCollection)); 275 } else if (node.importClause && node.importClause.namedBindings && 276 ts.isNamedImports(node.importClause.namedBindings) && node.importClause.namedBindings.elements) { 277 let nested: boolean = false; 278 node.importClause.namedBindings.elements.forEach(item => { 279 if (item.name && ts.isIdentifier(item.name) && asNameFromParent.has(item.name.escapedText.toString())) { 280 nested = true; 281 if (item.propertyName && ts.isIdentifier(item.propertyName)) { 282 asNameFromParent.set(item.propertyName.escapedText.toString(), 283 asNameFromParent.get(item.name.escapedText.toString())); 284 } 285 } 286 }); 287 if (nested) { 288 processImport(node, pagesDir, log, asNameFromParent, false, new Set(pathCollection)); 289 } 290 } 291 } 292 node.getChildren().reverse().forEach((item: ts.Node) => visitAllNode(item, sourceFile, 293 defaultNameFromParent, asNameFromParent, pagesDir, log, entryCollection, exportCollection, 294 defaultCollection, asExportCollection, pathCollection, fileResolvePath)); 295} 296 297function collectSpecialFunctionNode(node: ts.FunctionDeclaration | ts.ClassDeclaration | ts.StructDeclaration, 298 asNameFromParent: Map<string, string>, defaultNameFromParent: string, defaultCollection: Set<string>, 299 asExportCollection: Map<string, string>, collection: Set<string>): void { 300 const name: string = node.name.getText(); 301 let componentName: string; 302 if (asNameFromParent.has(name)) { 303 collection.add(asNameFromParent.get(name)); 304 } else if (node.modifiers && node.modifiers.length >= 1 && node.modifiers[0] && 305 node.modifiers[0].kind === ts.SyntaxKind.ExportKeyword) { 306 if (node.modifiers.length == 1) { 307 collection.add(name); 308 } else if (node.modifiers.length >= 2 && node.modifiers[1] && node.modifiers[1].kind === 309 ts.SyntaxKind.DefaultKeyword) { 310 collection.add(CUSTOM_COMPONENT_DEFAULT); 311 if (defaultNameFromParent && asNameFromParent.has(defaultNameFromParent)) { 312 collection.add(asNameFromParent.get(defaultNameFromParent)); 313 } 314 } 315 } else if (defaultCollection.has(name)) { 316 collection.add(CUSTOM_COMPONENT_DEFAULT); 317 } else if (asExportCollection.has(name)) { 318 collection.add(asExportCollection.get(name)); 319 } 320} 321 322function isExportEntry(node: ts.ClassDeclaration, log: LogInfo[], entryCollection: Set<string>, 323 exportCollection: Set<string>, defaultCollection: Set<string>, fileResolvePath: string, 324 sourceFile: ts.SourceFile): void { 325 if (process.env.watchMode === 'true' && node && node.decorators) { 326 let existExport: boolean = false; 327 let existEntry: boolean = false; 328 if (node.modifiers) { 329 for (let i = 0; i < node.modifiers.length; i++) { 330 if (node.modifiers[i].kind === ts.SyntaxKind.ExportKeyword) { 331 existExport = true; 332 break; 333 } 334 } 335 } 336 for (let i = 0; i < node.decorators.length; i++) { 337 if (node.decorators[i].getText() === COMPONENT_DECORATOR_ENTRY) { 338 entryCollection.add(node.name.escapedText.toString()); 339 existEntry = true; 340 break; 341 } 342 } 343 } 344} 345 346function remindExportEntryComponent(node: ts.Node, log: LogInfo[], fileResolvePath: string, 347 sourceFile: ts.SourceFile): void { 348 const posOfNode: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(node.getStart()); 349 const line: number = posOfNode.line + 1; 350 const column: number = posOfNode.character + 1; 351 const warnInfo: LogInfo = { 352 type: LogType.WARN, 353 message: `It's not a recommended way to export struct with @Entry decorator, ` + 354 `which may cause ACE Engine error in component preview mode.`, 355 pos: node.getStart(), 356 fileName: fileResolvePath, 357 line: line, 358 column: column 359 }; 360 if (!repeatLog.has(fileResolvePath)) { 361 log.push(warnInfo); 362 repeatLog.set(fileResolvePath, warnInfo); 363 } 364} 365 366function addDependencies(node: ts.ClassDeclaration, defaultNameFromParent: string, 367 asNameFromParent: Map<string, string>): void { 368 const componentName: string = node.name.getText(); 369 const ComponentSet: IComponentSet = getComponentSet(node); 370 if (defaultNameFromParent && node.modifiers && node.modifiers.length >= 2 && node.modifiers[0] && 371 node.modifiers[1] && node.modifiers[0].kind === ts.SyntaxKind.ExportKeyword && 372 node.modifiers[1].kind === ts.SyntaxKind.DefaultKeyword) { 373 setDependencies(defaultNameFromParent, ComponentSet.links, ComponentSet.properties, 374 ComponentSet.props, ComponentSet.builderParams, ComponentSet.states, ComponentSet.regulars, 375 ComponentSet.storageProps, ComponentSet.storageLinks, ComponentSet.provides, 376 ComponentSet.consumes, ComponentSet.objectLinks, ComponentSet.localStorageLink, 377 ComponentSet.localStorageProp, ComponentSet.builderParamData); 378 } else if (asNameFromParent.has(componentName)) { 379 setDependencies(asNameFromParent.get(componentName), ComponentSet.links, ComponentSet.properties, 380 ComponentSet.props, ComponentSet.builderParams, ComponentSet.states, ComponentSet.regulars, 381 ComponentSet.storageProps, ComponentSet.storageLinks, ComponentSet.provides, 382 ComponentSet.consumes, ComponentSet.objectLinks, ComponentSet.localStorageLink, 383 ComponentSet.localStorageProp, ComponentSet.builderParamData); 384 } else { 385 setDependencies(componentName, ComponentSet.links, ComponentSet.properties, ComponentSet.props, 386 ComponentSet.builderParams, ComponentSet.states, ComponentSet.regulars, 387 ComponentSet.storageProps, ComponentSet.storageLinks, ComponentSet.provides, 388 ComponentSet.consumes, ComponentSet.objectLinks, ComponentSet.localStorageLink, 389 ComponentSet.localStorageProp, ComponentSet.builderParamData); 390 } 391} 392 393function addDefaultExport(node: ts.ClassDeclaration | ts.ExportAssignment): void { 394 let name: string; 395 if (ts.isClassDeclaration(node) && node.name && ts.isIdentifier(node.name)) { 396 name = node.name.escapedText.toString(); 397 } else if (ts.isExportAssignment(node) && node.expression && ts.isIdentifier(node.expression)) { 398 name = node.expression.escapedText.toString(); 399 } else { 400 return; 401 } 402 setDependencies(CUSTOM_COMPONENT_DEFAULT, 403 linkCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 404 new Set([...linkCollection.get(CUSTOM_COMPONENT_DEFAULT), ...linkCollection.get(name)]) : 405 linkCollection.get(name), 406 propertyCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 407 new Set([...propertyCollection.get(CUSTOM_COMPONENT_DEFAULT), 408 ...propertyCollection.get(name)]) : propertyCollection.get(name), 409 propCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 410 new Set([...propCollection.get(CUSTOM_COMPONENT_DEFAULT), ...propCollection.get(name)]) : 411 propCollection.get(name), 412 builderParamObjectCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 413 new Set([...builderParamObjectCollection.get(CUSTOM_COMPONENT_DEFAULT), 414 ...builderParamObjectCollection.get(name)]) : builderParamObjectCollection.get(name), 415 stateCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 416 new Set([...stateCollection.get(CUSTOM_COMPONENT_DEFAULT), 417 ...stateCollection.get(name)]) : stateCollection.get(name), 418 regularCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 419 new Set([...regularCollection.get(CUSTOM_COMPONENT_DEFAULT), 420 ...regularCollection.get(name)]) : regularCollection.get(name), 421 storagePropCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 422 new Set([...storagePropCollection.get(CUSTOM_COMPONENT_DEFAULT), 423 ...storagePropCollection.get(name)]) : storagePropCollection.get(name), 424 storageLinkCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 425 new Set([...storageLinkCollection.get(CUSTOM_COMPONENT_DEFAULT), 426 ...storageLinkCollection.get(name)]) : storageLinkCollection.get(name), 427 provideCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 428 new Set([...provideCollection.get(CUSTOM_COMPONENT_DEFAULT), 429 ...provideCollection.get(name)]) : provideCollection.get(name), 430 consumeCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 431 new Set([...consumeCollection.get(CUSTOM_COMPONENT_DEFAULT), 432 ...consumeCollection.get(name)]) : consumeCollection.get(name), 433 objectLinkCollection.has(CUSTOM_COMPONENT_DEFAULT) ? 434 new Set([...objectLinkCollection.get(CUSTOM_COMPONENT_DEFAULT), 435 ...objectLinkCollection.get(name)]) : objectLinkCollection.get(name), 436 getNewLocalStorageMap(localStorageLinkCollection, name), 437 getNewLocalStorageMap(localStoragePropCollection, name), 438 builderParamInitialization.has(CUSTOM_COMPONENT_DEFAULT) ? 439 new Set([...builderParamInitialization.get(CUSTOM_COMPONENT_DEFAULT), 440 ...builderParamInitialization.get(name)]) : builderParamInitialization.get(name) 441 ); 442} 443 444function getNewLocalStorageMap(collection: Map<string, Map<string, Set<string>>>, name: string) 445 : Map<string, Set<string>> { 446 let localStorageLinkMap: Map<string, Set<string>> = new Map(); 447 if (collection.has(CUSTOM_COMPONENT_DEFAULT)) { 448 const tempSet: Set<string> = new Set(); 449 if (collection.get(CUSTOM_COMPONENT_DEFAULT)) { 450 for (const key of collection.get(CUSTOM_COMPONENT_DEFAULT).keys()) { 451 tempSet.add(key); 452 } 453 } 454 if (collection.get(name)) { 455 for (const key of collection.get(name).keys()) { 456 tempSet.add(key); 457 } 458 } 459 localStorageLinkMap.set(name, tempSet); 460 } else { 461 localStorageLinkMap = collection.get(name); 462 } 463 return localStorageLinkMap; 464} 465 466function setDependencies(component: string, linkArray: Set<string>, propertyArray: Set<string>, 467 propArray: Set<string>, builderParamArray: Set<string>, stateArray: Set<string>, 468 regularArray: Set<string>, storagePropsArray: Set<string>, storageLinksArray: Set<string>, 469 providesArray: Set<string>, consumesArray: Set<string>, objectLinksArray: Set<string>, 470 localStorageLinkMap: Map<string, Set<string>>, localStoragePropMap: Map<string, Set<string>>, 471 builderParamData: Set<string>): void { 472 linkCollection.set(component, linkArray); 473 propertyCollection.set(component, propertyArray); 474 propCollection.set(component, propArray); 475 builderParamObjectCollection.set(component, builderParamArray); 476 objectLinkCollection.set(component, objectLinksArray); 477 componentCollection.customComponents.add(component); 478 stateCollection.set(component, stateArray); 479 regularCollection.set(component, regularArray); 480 storagePropCollection.set(component, storagePropsArray); 481 storageLinkCollection.set(component, storageLinksArray); 482 provideCollection.set(component, providesArray); 483 consumeCollection.set(component, consumesArray); 484 objectLinkCollection.set(component, objectLinksArray); 485 localStorageLinkCollection.set(component, localStorageLinkMap); 486 localStoragePropCollection.set(component, localStoragePropMap); 487 builderParamInitialization.set(component, builderParamData); 488} 489 490function hasCollection(node: ts.Identifier): boolean { 491 const name: string = node.escapedText.toString(); 492 return linkCollection.has(name) || 493 propCollection.has(name) || 494 propertyCollection.has(name) || 495 builderParamObjectCollection.has(name) || 496 stateCollection.has(name) || 497 regularCollection.has(name) || 498 storagePropCollection.has(name) || 499 storageLinkCollection.has(name) || 500 provideCollection.has(name) || 501 consumeCollection.has(name) || 502 objectLinkCollection.has(name) || 503 localStorageLinkCollection.has(name) || 504 localStoragePropCollection.has(name) 505} 506 507function isModule(filePath: string): boolean { 508 return !/^(\.|\.\.)?\//.test(filePath) || filePath.indexOf(projectConfig.packageDir) > -1; 509} 510 511function isCustomComponent(node: ts.ClassDeclaration | ts.StructDeclaration): boolean { 512 if (node.decorators && node.decorators.length) { 513 for (let i = 0; i < node.decorators.length; ++i) { 514 const decoratorName: ts.Identifier = node.decorators[i].expression as ts.Identifier; 515 if (ts.isIdentifier(decoratorName) && 516 CUSTOM_DECORATOR_NAME.has(decoratorName.escapedText.toString())) { 517 return true; 518 } 519 } 520 } 521 return false; 522} 523 524let packageJsonEntry: string = ''; 525 526function isPackageJsonEntry(filePath: string): boolean { 527 const packageJsonPath: string = path.join(filePath, projectConfig.packageJson); 528 if (fs.existsSync(packageJsonPath)) { 529 let entryTypes: string; 530 let entryMain: string; 531 try { 532 const packageJson: Object = 533 (projectConfig.packageManagerType === 'npm' ? JSON : JSON5).parse(fs.readFileSync(packageJsonPath).toString()); 534 entryTypes = packageJson.types; 535 entryMain = packageJson.main; 536 } catch (e) { 537 return false; 538 } 539 if (entryExist(filePath, entryTypes)) { 540 packageJsonEntry = path.resolve(filePath, entryTypes); 541 return true; 542 } else if (entryExist(filePath, entryMain)) { 543 packageJsonEntry = path.resolve(filePath, entryMain); 544 return true; 545 } 546 } 547} 548 549function entryExist(filePath: string, entry: string): boolean { 550 return typeof entry === 'string' && fs.existsSync(path.resolve(filePath, entry)) && 551 fs.statSync(path.resolve(filePath, entry)).isFile(); 552} 553 554function getModuleFilePath(filePath: string): string { 555 if (filePath && path.extname(filePath) !== EXTNAME_ETS && isModule(filePath)) { 556 filePath += EXTNAME_ETS; 557 } 558 return filePath; 559} 560 561function getFileResolvePath(fileResolvePath: string, pagesDir: string, filePath: string, 562 projectPath: string): string { 563 const moduleFilePath: string = getModuleFilePath(filePath); 564 const defaultModule: string = path.join(projectPath, moduleFilePath); 565 if (fs.existsSync(defaultModule)) { 566 return defaultModule; 567 } 568 let entryModule: string; 569 let etsModule: string; 570 if (!projectConfig.aceModuleJsonPath) { 571 entryModule = path.join(projectPath, '../../../../../', moduleFilePath); 572 etsModule = path.join(projectPath, '../../', moduleFilePath); 573 } else { 574 entryModule = path.join(projectPath, '../../../../', moduleFilePath); 575 etsModule = path.join(projectPath, '../', moduleFilePath); 576 } 577 if (fs.existsSync(entryModule)) { 578 return entryModule; 579 } 580 if (fs.existsSync(etsModule)) { 581 return etsModule; 582 } 583 let curPageDir: string = pagesDir; 584 while (!fs.existsSync(fileResolvePath)) { 585 if (filePath.indexOf(projectConfig.packageDir) > -1) { 586 fileResolvePath = path.join(curPageDir, filePath); 587 } else { 588 fileResolvePath = path.join(curPageDir, projectConfig.packageDir, filePath); 589 } 590 if (fs.existsSync(fileResolvePath + EXTNAME_ETS)) { 591 fileResolvePath = fileResolvePath + EXTNAME_ETS; 592 } else if (isPackageJsonEntry(fileResolvePath)) { 593 fileResolvePath = packageJsonEntry; 594 if (fs.statSync(fileResolvePath).isDirectory()) { 595 if (fs.existsSync(path.join(fileResolvePath, INDEX_ETS))) { 596 fileResolvePath = path.join(fileResolvePath, INDEX_ETS); 597 } else if (fs.existsSync(path.join(fileResolvePath, INDEX_TS))) { 598 fileResolvePath = path.join(fileResolvePath, INDEX_TS); 599 } 600 } 601 } else if (fs.existsSync(path.join(fileResolvePath, INDEX_ETS))) { 602 fileResolvePath = path.join(fileResolvePath, INDEX_ETS); 603 } else if (fs.existsSync(path.join(fileResolvePath, INDEX_TS))) { 604 fileResolvePath = path.join(fileResolvePath, INDEX_TS); 605 } 606 if (curPageDir === path.parse(curPageDir).root) { 607 break; 608 } 609 curPageDir = path.dirname(curPageDir); 610 } 611 return fileResolvePath; 612} 613 614export function getFileFullPath(filePath: string, pagesDir: string): string { 615 if (filePath && path.extname(filePath) !== EXTNAME_ETS && path.extname(filePath) !== EXTNAME_TS && 616 !isModule(filePath)) { 617 const dirIndexEtsPath: string = path.resolve(path.resolve(pagesDir, filePath), INDEX_ETS); 618 const dirIndexTsPath: string = path.resolve(path.resolve(pagesDir, filePath), INDEX_TS); 619 if (/^(\.|\.\.)\//.test(filePath) && !fs.existsSync(path.resolve(pagesDir, filePath + EXTNAME_ETS)) && 620 fs.existsSync(dirIndexEtsPath)) { 621 filePath = dirIndexEtsPath; 622 } else if (/^(\.|\.\.)\//.test(filePath) && !fs.existsSync(path.resolve(pagesDir, filePath + EXTNAME_TS)) && 623 fs.existsSync(dirIndexTsPath)) { 624 filePath = dirIndexTsPath; 625 } else { 626 filePath += getExtensionIfUnfullySpecifiedFilepath(path.resolve(pagesDir, filePath)); 627 } 628 } 629 630 let fileResolvePath: string; 631 if (/^(\.|\.\.)\//.test(filePath) && filePath.indexOf(projectConfig.packageDir) < 0) { 632 fileResolvePath = path.resolve(pagesDir, filePath); 633 } else if (/^\//.test(filePath) && filePath.indexOf(projectConfig.packageDir) < 0 || 634 fs.existsSync(filePath) && fs.statSync(filePath).isFile()) { 635 fileResolvePath = filePath; 636 } else { 637 fileResolvePath = getFileResolvePath(fileResolvePath, pagesDir, filePath, projectConfig.projectPath); 638 } 639 640 return fileResolvePath; 641} 642 643function validateModuleName(moduleNode: ts.Identifier, log: LogInfo[], sourceFile?: ts.SourceFile, 644 fileResolvePath?: string): void { 645 const moduleName: string = moduleNode.escapedText.toString(); 646 if (INNER_COMPONENT_NAMES.has(moduleName)) { 647 const error: LogInfo = { 648 type: LogType.ERROR, 649 message: `The module name '${moduleName}' can not be the same as the inner component name.`, 650 pos: moduleNode.getStart() 651 }; 652 if (sourceFile && fileResolvePath) { 653 const posOfNode: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(moduleNode.getStart()); 654 const line: number = posOfNode.line + 1; 655 const column: number = posOfNode.character + 1; 656 Object.assign(error, { 657 fileName: fileResolvePath, 658 line: line, 659 column: column 660 }); 661 } 662 log.push(error); 663 } 664} 665