UNPKG

@o3r/components

Version:

This module contains component-related features (Component replacement, CMS compatibility, helpers, pipes, debugging developer tools...) It comes with an integrated ng builder to help you generate components compatible with Otter features (CMS integration

133 lines 7.11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ComponentParser = void 0; const tslib_1 = require("tslib"); const path = tslib_1.__importStar(require("node:path")); const schematics_1 = require("@o3r/schematics"); const globby_1 = tslib_1.__importDefault(require("globby")); const ts = tslib_1.__importStar(require("typescript")); const component_class_extractor_1 = require("./component-class.extractor"); const component_config_extractor_1 = require("./component-config.extractor"); /** * Component extractor parser. */ class ComponentParser { /** * Component extractor parser constructor * @param libraryName * @param tsconfigPath Path to the tsconfig defining the list of path to parse * @param logger Logger * @param strictMode * @param libraries * @param globalConfigCategories */ constructor(libraryName, tsconfigPath, logger, strictMode = false, libraries = [], globalConfigCategories = []) { this.libraryName = libraryName; this.tsconfigPath = tsconfigPath; this.logger = logger; this.strictMode = strictMode; this.libraries = libraries; this.globalConfigCategories = globalConfigCategories; this.globalConfigCategoriesMap = new Map(this.globalConfigCategories.map((category) => [category.name, category.label])); } /** Get the list of patterns from tsconfig.json */ getPatternsFromTsConfig() { const tsconfigResult = ts.readConfigFile(this.tsconfigPath, (p) => ts.sys.readFile(p)); if (tsconfigResult.error) { const errorMessage = typeof tsconfigResult.error.messageText === 'string' ? tsconfigResult.error.messageText : tsconfigResult.error.messageText.messageText; this.logger.error(errorMessage); throw new schematics_1.O3rCliError(errorMessage); } const include = [...(tsconfigResult.config.files || []), ...(tsconfigResult.config.include || [])]; const exclude = tsconfigResult.config.exclude || []; const cwd = path.resolve(path.dirname(this.tsconfigPath), tsconfigResult.config.rootDir || '.'); return { include, exclude, cwd }; } /** Get the list of file from tsconfig.json */ getFilesFromTsConfig() { const { include, exclude, cwd } = this.getPatternsFromTsConfig(); return (0, globby_1.default)(include, { ignore: exclude, cwd, absolute: true }); } /** * Extract a component of a given file * @param file Path to the file to extract the component from * @param source Typescript SourceFile node of the file */ getComponent(file, source) { const componentExtractor = new component_class_extractor_1.ComponentClassExtractor(source, this.logger, file); return componentExtractor.extract(); } /** * Extract a configuration of a given file * @param file Path to the file to extract the configuration from * @param source Typescript SourceFile node of the file * @param checker Typescript TypeChecker of the program */ getConfiguration(file, source, checker) { const configurationFileExtractor = new component_config_extractor_1.ComponentConfigExtractor(this.libraryName, this.strictMode, source, this.logger, file, checker, this.libraries); const configuration = configurationFileExtractor.extract(); if (configuration.configurationInformation) { (configuration.configurationInformation.categories || []).forEach((category) => { if (this.globalConfigCategoriesMap.has(category.name)) { this.logger.warn(`The category ${category.name} is already defined in the global ones.`); } }); const categoriesMap = new Map((configuration.configurationInformation.categories || []).map((category) => [category.name, category.label])); configuration.configurationInformation.properties.forEach((prop) => { if (prop.category && !categoriesMap.has(prop.category)) { if (this.globalConfigCategoriesMap.has(prop.category)) { categoriesMap.set(prop.category, this.globalConfigCategoriesMap.get(prop.category)); } else { this.logger.warn(`The property ${prop.name} from ${configuration.configurationInformation.name} has an unknown category ${prop.category}. The category will not be set for this property.`); delete prop.category; } } }); const categories = Array.from(categoriesMap).map(([name, label]) => ({ name, label })); configuration.configurationInformation.categories = categories.length > 0 ? categories : undefined; if (this.strictMode) { configuration.configurationInformation.properties = configuration.configurationInformation.properties .filter((prop) => { const res = !(new RegExp(`^${configurationFileExtractor.DEFAULT_UNKNOWN_TYPE}`).test(prop.type)); if (!res) { this.logger.warn(`The property ${prop.name} from ${configuration.configurationInformation.name} has unknown type, it will be filtered from metadata.`); } return res; }); } } return configuration; } /** * Extract the Components and Configurations implemented in each files from tsconfig * */ async parse() { const filePaths = await this.getFilesFromTsConfig(); const program = ts.createProgram(filePaths, {}); const checker = program.getTypeChecker(); const components = {}; const configurations = {}; // Here for each file we will go through all the extractors because we can't rely on file pattern only // We need to perform some logic before figuring out if we are dealing with a config or component // This approach allow to support the configuration in the same file that the component (not recommended) filePaths.forEach((filePath) => { this.logger.debug(`Parsing ${filePath}`); const source = program.getSourceFile(filePath); if (source) { const configurationFromSource = this.getConfiguration(filePath, source, checker); if (configurationFromSource.configurationInformation || configurationFromSource.nestedConfiguration) { configurations[filePath] = { configuration: configurationFromSource, file: filePath }; } const componentFromSource = this.getComponent(filePath, source); if (componentFromSource) { components[filePath] = { component: componentFromSource, file: filePath }; } } }); return { components, configurations }; } } exports.ComponentParser = ComponentParser; //# sourceMappingURL=component.parser.js.map