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