UNPKG

@oasisdigital/ng-doc-portal-plugin

Version:

Nx plugin for adding the ng-doc-portal system to your nx workspace

257 lines (256 loc) 9.27 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.accumulatePayloads = accumulatePayloads; exports.sortFullPayloadList = sortFullPayloadList; exports.insertIntoSortedPayloadList = insertIntoSortedPayloadList; exports.comparePayloadTitles = comparePayloadTitles; exports.findTitlePrefixFromGlobPatterns = findTitlePrefixFromGlobPatterns; exports.generateTitleFromFilePath = generateTitleFromFilePath; exports.getTitleFromTypeScript = getTitleFromTypeScript; exports.extractTitleFromDocPageFile = extractTitleFromDocPageFile; exports.generateDocPageLoader = generateDocPageLoader; exports.formatContent = formatContent; exports.wrapTypescriptBoilerplate = wrapTypescriptBoilerplate; exports.convertPatternOrGlobPatternArray = convertPatternOrGlobPatternArray; exports.timeNow = timeNow; const tslib_1 = require("tslib"); const tsquery_1 = require("@phenomnomnominal/tsquery"); const date_fns_1 = require("date-fns"); const minimatch_1 = require("minimatch"); const prettier_1 = require("prettier"); const fs_1 = require("fs"); const path_1 = require("path"); /** * Extract all the payloads from the various processed file events. * * @param acc The previous accumulated payloads * @param curr The current file event */ function accumulatePayloads(acc, curr) { if (curr.type === 'init') { const list = sortFullPayloadList(curr.payload); return list; } else if (curr.type === 'add') { return insertIntoSortedPayloadList(acc, { filePath: curr.filePath, title: curr.title, }); } else if (curr.type === 'unlink') { return acc.filter((f) => f.filePath !== curr.filePath); } else if (curr.type === 'change') { const index = acc.findIndex((f) => f.filePath === curr.filePath); if (index < 0) { return acc; } const copy = [...acc]; copy[index] = { filePath: curr.filePath, title: curr.title, }; return copy; } // Can't happen, but needed for the compiler return []; } function sortFullPayloadList(list) { return list.sort(comparePayloadTitles); } function insertIntoSortedPayloadList(list, item) { let index = 0; let low = 0; let mid = -1; let high = list.length; let c = 0; while (low < high) { mid = Math.floor((low + high) / 2); c = comparePayloadTitles(list[mid], item); if (c < 0) { low = mid + 1; } else if (c > 0) { high = mid; } else { index = mid; break; } } index = low; list.splice(index, 0, item); return list; } function comparePayloadTitles(a, b) { if (a.title > b.title) { return 1; } else if (a.title < b.title) { return -1; } else { return 0; } } function findTitlePrefixFromGlobPatterns(filePath, globPatterns) { const pattern = globPatterns.find((globPattern) => { if (typeof globPattern === 'string') { return (0, minimatch_1.minimatch)(filePath, globPattern); } else { return (0, minimatch_1.minimatch)(filePath, globPattern.pattern); } }); if (!pattern || typeof pattern === 'string') { return undefined; } else { let prefix = pattern.titlePrefix; // Some quick cleanup just in case folks put `/` characters at start/end of prefix while (prefix && prefix.endsWith('/')) { prefix = prefix.slice(0, -1); } while (prefix && prefix.startsWith('/')) { prefix = prefix.slice(1); } // --- return prefix; } } function generateTitleFromFilePath(filePath) { const baseName = (0, path_1.basename)(filePath); const fileName = baseName.substring(0, baseName.indexOf('.')); const words = fileName.split('-'); let title = ''; for (let word of words) { word = word.charAt(0).toUpperCase() + word.substring(1); if (title) { title = `${title} ${word}`; } else { title = word; } } return title.charAt(0).toUpperCase() + title.substring(1); } function getTitleFromTypeScript(filePath) { return tslib_1.__awaiter(this, void 0, void 0, function* () { var _a; const rawTS = (0, fs_1.readFileSync)('./' + filePath).toString(); const ast = tsquery_1.tsquery.ast(rawTS); const defaultExportClassDeclaration = (0, tsquery_1.tsquery)(ast, 'ClassDeclaration:has(ExportKeyword):has(DefaultKeyword)').at(0); if (defaultExportClassDeclaration) { // generate title dynamically // TODO: Add folder structure to title generated here // Should be based off whatever glob picked up this file return generateTitleFromFilePath(filePath); } else { // Find ExportAssignment in the TS file const exportAssignment = (0, tsquery_1.tsquery)(ast, 'ExportAssignment').at(0); if (exportAssignment) { // There are two paths on this front // Either there is an in-line ObjectLiteral // Or there is an identifier that points to a VariableDeclaration // with the ObjectLiteral let objectLiteralExpression = (0, tsquery_1.tsquery)(exportAssignment, 'ObjectLiteralExpression').at(0); if (!objectLiteralExpression) { const identifier = (0, tsquery_1.tsquery)(exportAssignment, 'Identifier').at(0); objectLiteralExpression = (0, tsquery_1.tsquery)(ast, `VariableDeclaration:has(Identifier[name="${identifier === null || identifier === void 0 ? void 0 : identifier.getText(ast)}"]) > ObjectLiteralExpression`).at(0); } if (objectLiteralExpression) { // Once the ObjectLiteral is found // Find the `title` property's string value const title = (_a = (0, tsquery_1.tsquery)(objectLiteralExpression, 'PropertyAssignment:has(Identifier[name="title"]) > StringLiteral') .at(0)) === null || _a === void 0 ? void 0 : _a.getText(ast); if (title) { // For some reason `.getText()` returns the quotes of the string return title.replace(/'/g, ''); } else { throw new Error(`No property found for 'title' in exported object literal for file: ${filePath}`); } } else { throw new Error(`No object literal export found for file: ${filePath}`); } } else { throw new Error(`No exports found for file: ${filePath}`); } } }); } /** * Extract the title from the doc page file's config * * @param filePath The location of the file. Both the filename and the * contents of the file will be used to extract title from the config in the file */ function extractTitleFromDocPageFile(filePath, globPatterns) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const title = yield getTitleFromTypeScript(filePath); const prefix = findTitlePrefixFromGlobPatterns(filePath, globPatterns); if (prefix) { return `${prefix}/${title}`; } else { return title; } }); } /** * Generate the doc page loader from the filePath and the title. * * @param filePath The original filePath (with '.ts') * @param title The title for the file */ function generateDocPageLoader(filePath, title) { // Figure out variables for config list file output const filePathWithoutExtension = filePath.replace('.ts', ''); const route = title.toLowerCase().replace(/[ /]/g, '-'); return ` '${route}': { title: '${title}', fetch: () => import('../../../../${filePathWithoutExtension}').then((file) => file.default) } `; } /** * Prettier formats any file content string passed in * * @param content The file content to be prettified */ function formatContent(content) { return tslib_1.__awaiter(this, void 0, void 0, function* () { return (0, prettier_1.format)(content, { parser: 'typescript', printWidth: 100, singleQuote: true, }); }); } /** * Generate the text of formatted TypeScript file around the config strings. * * @param configStrings The config strings generated from our path files */ function wrapTypescriptBoilerplate(configStrings) { return ` /* eslint-disable */ import { DocPageLoaderRecord } from '@oasisdigital/ng-doc-portal'; export const docPageLoaders: DocPageLoaderRecord = { ${configStrings.toString()} }; `; } function convertPatternOrGlobPatternArray(patterns) { return patterns.map((strOrGlobPattern) => typeof strOrGlobPattern === 'string' ? strOrGlobPattern : strOrGlobPattern.pattern); } function timeNow() { return (0, date_fns_1.format)(new Date(), 'HH:mm:ss:SSS'); } //# sourceMappingURL=util.js.map