UNPKG

nativescript

Version:

Command-line interface for building NativeScript projects

235 lines • 12.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.HelpService = void 0; const path = require("path"); const os_1 = require("os"); const marked_1 = require("marked"); const yok_1 = require("../yok"); const _ = require("lodash"); class HelpService { get newLineRegex() { return /\r?\n/g; } get pathToStylesCss() { return path.join(this.$staticConfig.HTML_COMMON_HELPERS_DIR, "styles.css"); } get pathToBasicPage() { return path.join(this.$staticConfig.HTML_COMMON_HELPERS_DIR, "basic-page.html"); } get pathToBasicPageForExtensions() { return path.join(this.$staticConfig.HTML_COMMON_HELPERS_DIR, "basic-extensions-page.html"); } get pathToIndexHtml() { return path.join(this.$staticConfig.HTML_PAGES_DIR, "index.html"); } constructor($logger, $injector, $errors, $fs, $staticConfig, $extensibilityService, $microTemplateService, $opener) { this.$logger = $logger; this.$injector = $injector; this.$errors = $errors; this.$fs = $fs; this.$staticConfig = $staticConfig; this.$extensibilityService = $extensibilityService; this.$microTemplateService = $microTemplateService; this.$opener = $opener; this.pathToImages = this.$staticConfig.HTML_CLI_HELPERS_DIR; this.pathToHtmlPages = this.$staticConfig.HTML_PAGES_DIR; this.pathToManPages = this.$staticConfig.MAN_PAGES_DIR; } async openHelpForCommandInBrowser(commandData) { const { commandName } = commandData; const htmlPage = (await this.convertCommandNameToFileName(commandData)) + HelpService.HTML_FILE_EXTENSION; this.$logger.trace("Opening help for command '%s'. FileName is '%s'.", commandName, htmlPage); this.$fs.ensureDirectoryExists(this.pathToHtmlPages); if (!this.tryOpeningSelectedPage(htmlPage)) { // HTML pages may have been skipped on post-install, lets generate them. this.$logger.trace("Required HTML file '%s' is missing. Let's try generating HTML files and see if we'll find it.", htmlPage); await this.generateHtmlPages(); if (!this.tryOpeningSelectedPage(htmlPage)) { this.$errors.fail("Unable to find help for '%s'", commandName); } } } async generateHtmlPages() { const mdFiles = this.$fs.enumerateFilesInDirectorySync(this.pathToManPages); const basicHtmlPage = this.$fs.readText(this.pathToBasicPage); await Promise.all(_.map(mdFiles, (markdownFile) => { const htmlPageGenerationData = { basicHtmlPage, pathToMdFile: markdownFile, pathToMdPages: this.pathToManPages, pathToHtmlPages: this.pathToHtmlPages, }; return this.createHtmlPage(htmlPageGenerationData); })); const installedExtensionsData = this.$extensibilityService.getInstalledExtensionsData(); const basicHtmlPageForExtensions = this.$fs.readText(this.pathToBasicPageForExtensions); for (const extensionData of installedExtensionsData) { const docsDir = extensionData.docs; if (docsDir) { this.$logger.trace(`Start generation of html help content for extension ${extensionData.extensionName}`); if (!this.$fs.exists(docsDir)) { this.$logger.warn(`Unable to generate html help pages for extension ${extensionData.extensionName} as the docs directory ${docsDir} does not exist.`); continue; } const htmlDirFullPath = HelpService.getHtmlDirFullPath(docsDir); this.$fs.ensureDirectoryExists(htmlDirFullPath); const extensionMdFiles = this.$fs.enumerateFilesInDirectorySync(docsDir); try { await Promise.all(_.map(extensionMdFiles, (markdownFile) => { const htmlPageGenerationData = { basicHtmlPage: basicHtmlPageForExtensions, pathToMdFile: markdownFile, pathToMdPages: docsDir, pathToHtmlPages: htmlDirFullPath, extensionName: extensionData.extensionName, }; return this.createHtmlPage(htmlPageGenerationData); })); } catch (err) { this.$logger.warn(`Unable to generate html help for extension ${extensionData.extensionName}. Error is: ${err.message}`); } this.$logger.trace(`Finished generation of html help content for extension ${extensionData.extensionName}`); } } this.$logger.trace("Finished generating HTML files."); } async showCommandLineHelp(commandData) { const help = await this.getCommandLineHelpForCommand(commandData); this.$logger.printMarkdown(help); } /** * Gets the help content for a specific command that should be shown on the terminal. * @param {string} commandName Name of the command for which to read the help. * @returns {Promise<string>} Help content of the command parsed with all terminal rules applied (stripped content that should be shown only for html help). */ async getCommandLineHelpForCommand(commandData) { const helpText = await this.readMdFileForCommand(commandData); const commandLineHelp = (await this.$microTemplateService.parseContent(helpText, { isHtml: false })) .replace(/&nbsp;/g, " ") .replace(HelpService.MARKDOWN_LINK_REGEX, "$1") .replace(HelpService.SPAN_REGEX, (matchingSubstring, textBeforeSpan, textInsideSpan, index, fullString) => { return textBeforeSpan + textInsideSpan.replace(this.newLineRegex, ""); }) .replace(HelpService.NEW_LINE_REGEX, os_1.EOL); return commandLineHelp; } // This method should return Promise in order to generate all html pages simultaneously. async createHtmlPage(htmlPageGenerationData) { const { basicHtmlPage, pathToMdFile, pathToMdPages, pathToHtmlPages, extensionName, } = htmlPageGenerationData; const mdFileName = path.basename(pathToMdFile); const htmlFileName = mdFileName.replace(HelpService.MARKDOWN_FILE_EXTENSION, HelpService.HTML_FILE_EXTENSION); this.$logger.trace("Generating '%s' help topic.", htmlFileName); const helpText = this.$fs.readText(pathToMdFile); const outputText = await this.$microTemplateService.parseContent(helpText, { isHtml: true, }); const htmlText = await (0, marked_1.marked)(outputText); const filePath = pathToMdFile .replace(path.basename(pathToMdPages), path.basename(pathToHtmlPages)) .replace(mdFileName, htmlFileName); this.$logger.trace("HTML file path for '%s' man page is: '%s'.", mdFileName, filePath); let outputHtml = basicHtmlPage .replace(HelpService.MAN_PAGE_NAME_REGEX, mdFileName.replace(HelpService.MARKDOWN_FILE_EXTENSION, "")) .replace(HelpService.HTML_COMMAND_HELP_REGEX, htmlText) .replace(HelpService.RELATIVE_PATH_TO_STYLES_CSS_REGEX, path.relative(path.dirname(filePath), this.pathToStylesCss)) .replace(HelpService.RELATIVE_PATH_TO_IMAGES_REGEX, path.relative(path.dirname(filePath), this.pathToImages)) .replace(HelpService.RELATIVE_PATH_TO_INDEX_REGEX, path.relative(path.dirname(filePath), this.pathToIndexHtml)); if (extensionName) { outputHtml = outputHtml.replace(HelpService.EXTENSION_NAME_REGEX, extensionName); } this.$fs.writeFile(filePath, outputHtml); this.$logger.trace("Finished writing file '%s'.", filePath); } async convertCommandNameToFileName(commandData) { let { commandName } = commandData; const defaultCommandMatch = commandName && commandName.match(/([\w-]+?)\|\*/); if (defaultCommandMatch) { this.$logger.trace("Default command found. Replace current command name '%s' with '%s'.", commandName, defaultCommandMatch[1]); commandName = defaultCommandMatch[1]; } const availableCommands = this.$injector .getRegisteredCommandsNames(true) .sort(); this.$logger.trace("List of registered commands: %s", availableCommands.join(", ")); if (commandName && !_.includes(availableCommands, commandName)) { await this.throwMissingCommandError(commandData); } return (commandName && commandName.replace(/\|/g, "-")) || "start"; } async throwMissingCommandError(commandData) { const commandName = commandData.commandName; const commandInfo = { inputStrings: [commandName, ...commandData.commandArguments], commandDelimiter: "|" /* CommandsDelimiters.HierarchicalCommand */, defaultCommandDelimiter: "|*" /* CommandsDelimiters.DefaultHierarchicalCommand */, }; const extensionData = await this.$extensibilityService.getExtensionNameWhereCommandIsRegistered(commandInfo); if (extensionData) { this.$errors.fail(extensionData.installationMessage); } this.$errors.fail("Unknown command '%s'. Try '$ %s help' for a full list of supported commands.", commandName, this.$staticConfig.CLIENT_NAME.toLowerCase()); } static getHtmlDirFullPath(docsDir) { return path.join(path.dirname(docsDir), "html"); } getHelpFile(searchedFileName, dirToCheck, getFullPathAction) { const fileList = this.$fs.enumerateFilesInDirectorySync(dirToCheck); let fileToOpen = _.find(fileList, (file) => path.basename(file) === searchedFileName); if (!fileToOpen) { fileToOpen = this.getHelpFileFromExtensions(searchedFileName, getFullPathAction); } return fileToOpen; } getHelpFileFromExtensions(searchedFileName, getFullPathAction) { const installedExtensionsData = this.$extensibilityService.getInstalledExtensionsData(); for (const extensionData of installedExtensionsData) { const docsDir = extensionData.docs; if (docsDir) { const fullPath = getFullPathAction ? getFullPathAction(docsDir) : docsDir; const fileToOpen = this.$fs.exists(fullPath) && _.find(this.$fs.enumerateFilesInDirectorySync(fullPath), (file) => path.basename(file) === searchedFileName); if (fileToOpen) { return fileToOpen; } } } } tryOpeningSelectedPage(htmlPage) { const pageToOpen = this.getHelpFile(htmlPage, this.pathToHtmlPages, HelpService.getHtmlDirFullPath); if (pageToOpen) { this.$logger.trace("Found page to open: '%s'", pageToOpen); this.$opener.open(pageToOpen, ""); return true; } this.$logger.trace("Unable to find file: '%s'", htmlPage); return false; } async readMdFileForCommand(commandData) { const mdFileName = (await this.convertCommandNameToFileName(commandData)) + HelpService.MARKDOWN_FILE_EXTENSION; this.$logger.trace("Reading help for command '%s'. FileName is '%s'.", commandData.commandName, mdFileName); const markdownFile = this.getHelpFile(mdFileName, this.pathToManPages); if (markdownFile) { return this.$fs.readText(markdownFile); } await this.throwMissingCommandError(commandData); } } exports.HelpService = HelpService; HelpService.MARKDOWN_FILE_EXTENSION = ".md"; HelpService.HTML_FILE_EXTENSION = ".html"; HelpService.MAN_PAGE_NAME_REGEX = /@MAN_PAGE_NAME@/g; HelpService.HTML_COMMAND_HELP_REGEX = /@HTML_COMMAND_HELP@/g; HelpService.RELATIVE_PATH_TO_STYLES_CSS_REGEX = /@RELATIVE_PATH_TO_STYLES_CSS@/g; HelpService.RELATIVE_PATH_TO_IMAGES_REGEX = /@RELATIVE_PATH_TO_IMAGES@/g; HelpService.RELATIVE_PATH_TO_INDEX_REGEX = /@RELATIVE_PATH_TO_INDEX@/g; HelpService.EXTENSION_NAME_REGEX = /@EXTENSION_NAME@/g; HelpService.MARKDOWN_LINK_REGEX = /\[([\w \-\`\<\>\*\:\\]+?)\]\([\s\S]+?\)/g; HelpService.SPAN_REGEX = /([\s\S]*?)(?:\r?\n)?<span.*?>([\s\S]*?)<\/span>(?:\r?\n)*/g; HelpService.NEW_LINE_REGEX = /<\/?\s*?br\s*?\/?>/g; // <br>, <br > <br/> <br /> yok_1.injector.register("helpService", HelpService); //# sourceMappingURL=help-service.js.map