UNPKG

nav-new-publication-cli

Version:

Add new publication to the navigator web project

490 lines (489 loc) 21.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.updateFile = updateFile; exports.updateFiles = updateFiles; const path = __importStar(require("path")); const fs = __importStar(require("fs/promises")); const path_1 = require("path"); const fs_extra_1 = require("fs-extra"); const utils_1 = require("./utils"); // Configuration for all files that need to be managed const fileConfigs = { storybookPreview: { path: '.storybook/preview.js', mode: 'update', findInsertionPoints: (lines, _publication) => { const points = {}; // Find the last import statement for each section for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (line.startsWith('import') && line.includes('css-loader!./themes/') && line.endsWith('.css\';')) { if (line.includes('lazyStyleTag')) { points.lazyImport = i; } else { points.regularImport = i; } } // Find cssList section if (line.includes('const cssList = {')) { points.cssList = i; // Find the closing brace of cssList for (let j = i + 1; j < lines.length; j++) { if (lines[j].trim().startsWith('}')) { points.cssListEnd = j; break; } } } // Find cssVariables.files section if (line.includes('cssVariables: {')) { for (let j = i + 1; j < lines.length; j++) { if (lines[j].includes('files: {')) { points.cssVarFiles = j; // Find the closing brace of files for (let k = j + 1; k < lines.length; k++) { if (lines[k].trim() === '},') { points.cssVarFilesEnd = k; break; } } break; } } } } return points; }, generateContent: async (publication) => { const publicationName = publication.stackAlias || publication.title.toLowerCase().replace(/\s/g, ''); return { lazyImport: `import ${publicationName} from '!!style-loader?injectType=lazyStyleTag!css-loader!./themes/${publicationName}.css';`, regularImport: `import ${publicationName}Css from '!css-loader!./themes/${publicationName}.css';`, cssList: ` ${publicationName}: ${publicationName}Css,`, cssVarFiles: ` ${publicationName}: ${publicationName},` }; } }, localProxy: { path: 'configs/localProxy.config.js', mode: 'update', findInsertionPoints: (lines, _publication) => { const points = {}; // Find the domainName object for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (line.startsWith('const domainName = {')) { // Find the closing brace of domainName for (let j = i + 1; j < lines.length; j++) { if (lines[j].trim() === '};') { points.domainMapEnd = j; break; } } break; } } return points; }, generateContent: async (publication) => { const publicationName = publication.stackAlias || publication.title.toLowerCase().replace(/\s/g, ''); return { domainMapEnd: ` ${publicationName}: '${publication.domain}',` }; } }, publicationJson: { path: 'drone/publication.json', mode: 'update', findInsertionPoints: (lines, publication) => { const points = {}; try { // Match: "<platform>": [ const keyRe = new RegExp(`^"${publication.platform}"\\s*:\\s*\\[$`); for (let i = 0; i < lines.length; i++) { const trimmed = lines[i].trim(); if (keyRe.test(trimmed)) { // IMPORTANT: insert immediately AFTER the '[' line, // so we appear BEFORE the original first '{' points.platformArray = i; // engine inserts AFTER this line break; } } return points; } catch (error) { (0, utils_1.logError)('Error parsing publication.json', error); return points; } }, generateContent: async (publication) => { const newPublication = { title: publication.title, export: { vr: publication.vr, functional: publication.func, }, domain: publication.domain, }; if (publication.stackAlias) { newPublication.stackAlias = publication.stackAlias; } // Pretty-print and indent to match array items (4 spaces) const body = JSON.stringify(newPublication, null, 2) .split('\n') .map(l => ' ' + l) .join('\n'); // Insert on its own line, with a trailing comma for separation return { platformArray: `\n${body},\n` }; } }, infrastructureConfig: { path: 'infrastructure/configs/publications/@PUBLICATION@.ts', mode: 'create', generateContent: async (publication) => { var _a, _b, _c, _d, _e, _f, _g, _h; const templatePath = path.join(__dirname, '../template/infrastucture.txt'); const template = await fs.readFile(templatePath, 'utf8'); const publicationName = publication.stackAlias || (publication.title ? publication.title.toLowerCase().replace(/\s/g, '') : 'default'); const upperName = publicationName.toUpperCase(); // Replace placeholders with appropriate casing let modifiedTemplate = template; modifiedTemplate = modifiedTemplate .replace(/@PUBLICATION_UPPER@/g, upperName) .replace(/@PUBLICATION_LOWER@/g, publicationName); modifiedTemplate = modifiedTemplate.replace(/@DOMAIN@/g, publication.domain || ''); modifiedTemplate = modifiedTemplate.replace(/@TITLE@/g, publication.title || ''); modifiedTemplate = modifiedTemplate.replace(/@STACKALIAS@/g, publicationName); // Ensure ARNs are properly quoted modifiedTemplate = modifiedTemplate.replace(/@DEVARN@/g, `'${((_a = publication.arn) === null || _a === void 0 ? void 0 : _a.dev) || ''}'`); modifiedTemplate = modifiedTemplate.replace(/@QAVARN@/g, `'${((_b = publication.arn) === null || _b === void 0 ? void 0 : _b.qa) || ''}'`); modifiedTemplate = modifiedTemplate.replace(/@PREPRODARN@/g, `'${((_c = publication.arn) === null || _c === void 0 ? void 0 : _c.preprod) || ''}'`); modifiedTemplate = modifiedTemplate.replace(/@PRODARN@/g, `'${((_d = publication.arn) === null || _d === void 0 ? void 0 : _d.prod) || ''}'`); modifiedTemplate = modifiedTemplate.replace(/@MINCAPACITY@/g, ((_f = (_e = publication.autoScaling) === null || _e === void 0 ? void 0 : _e.min) !== null && _f !== void 0 ? _f : 5).toString()); modifiedTemplate = modifiedTemplate.replace(/@MAXCAPACITY@/g, ((_h = (_g = publication.autoScaling) === null || _g === void 0 ? void 0 : _g.max) !== null && _h !== void 0 ? _h : 20).toString()); return { content: modifiedTemplate, path: `infrastructure/configs/publications/${publicationName}.ts` }; } }, webFargate: { path: 'infrastructure/configs/web-fargate.ts', mode: 'update', findInsertionPoints: (lines, _publication) => { const points = {}; // Find the first import statement for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (line.startsWith('import')) { points.imports = i; break; } } // Find the webConfigData spread for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (line.startsWith('const webConfigData = {')) { // Find the closing brace for (let j = i + 1; j < lines.length; j++) { if (lines[j].trim().startsWith('} as const;')) { points.configSpread = j; break; } } break; } } return points; }, generateContent: (publication) => { const publicationName = publication.stackAlias || publication.title.toLowerCase().replace(/\s/g, ''); const upperName = publicationName.toUpperCase(); return { imports: `import ${upperName} from './publications/${publicationName}';`, configSpread: ` ...${upperName},` }; } }, constants: { path: 'src/constants/config.ts', mode: 'update', findInsertionPoints: (lines, _publication) => { const points = {}; // Find PUBLICATIONS array for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (line.startsWith('export const PUBLICATIONS = [')) { points.publications = i; // Find the closing bracket for (let j = i + 1; j < lines.length; j++) { if (lines[j].trim().startsWith('] as const;')) { points.publicationsEnd = j; break; } } } // Find ENVIRONMENTS object if (line.startsWith('export const ENVIRONMENTS = {')) { points.environments = i; // Find the closing brace for (let j = i + 1; j < lines.length; j++) { if (lines[j].trim().startsWith('} as const;')) { points.environmentsEnd = j; break; } } } } return points; }, generateContent: (publication) => { const publicationName = publication.stackAlias || publication.title.toLowerCase().replace(/\s/g, ''); const upperName = publicationName.toUpperCase(); // For publications array, add to the end before closing bracket const publicationsContent = ` '${publicationName}',`; // For environments object, add all environments before closing brace const environmentsContent = [ ` DEV_${upperName}: 'dev_${publicationName}',`, ` QA_${upperName}: 'qa_${publicationName}',`, ` PREPROD_${upperName}: 'preprod_${publicationName}',`, ` PROD_${upperName}: 'prod_${publicationName}',` ].join('\n'); return { publications: publicationsContent, environments: environmentsContent }; } }, publications: { path: 'src/constants/publications.ts', mode: 'update', findInsertionPoints: (lines, _publication) => { const points = {}; // Find the interface definition for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (line.startsWith('interface PublicationConstants {')) { points.interface = i; // Find the closing brace of interface for (let j = i + 1; j < lines.length; j++) { if (lines[j].trim() === '}') { points.interfaceEnd = j; break; } } } // Find PUBLICATIONS constant if (line.startsWith('const PUBLICATIONS: Readonly<PublicationConstants> = {')) { points.publications = i; // Find the closing brace for (let j = i + 1; j < lines.length; j++) { if (lines[j].trim() === '};') { points.publicationsEnd = j; break; } } } } return points; }, generateContent: (publication) => { const publicationName = publication.stackAlias || publication.title.toLowerCase().replace(/\s/g, ''); const upperName = publicationName.toUpperCase(); return { interface: ` ${upperName}: string;`, publications: ` ${upperName}: '${publicationName}',` }; } }, publicationMap: { path: 'src/helpers/utils/publicationMap.ts', mode: 'update', findInsertionPoints: (lines, _publication) => { const points = {}; // Find the last publicationMap.set line for (let i = lines.length - 1; i >= 0; i--) { const line = lines[i].trim(); if (line.startsWith('publicationMap.set(')) { points.mapSet = i; break; } } return points; }, generateContent: (publication) => { const publicationName = publication.stackAlias || publication.title.toLowerCase().replace(/\s/g, ''); return { mapSet: `publicationMap.set('${publicationName}', '${publication.domain}');` }; } }, publicationsTest: { path: 'tests/unit/constants/publications.test.ts', mode: 'update', findInsertionPoints: (lines, _publication) => { const points = {}; // Find the expected object entries for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (line === 'const expected = {') { // Find all publication entries const entries = []; for (let j = i + 1; j < lines.length; j++) { const entryLine = lines[j].trim(); if (entryLine === '};') break; if (entryLine.includes(':')) { entries.push(entryLine); } } // Point to insert before the last entry points.insertBefore = i + entries.length; break; } } return points; }, generateContent: (publication) => { const publicationName = publication.stackAlias || publication.title.toLowerCase().replace(/\s/g, ''); const upperName = publicationName.toUpperCase(); return { insertBefore: ` ${upperName}: '${publicationName}',` }; } }, platformsMap: { path: 'src/helpers/utils/platforms.ts', mode: 'update', findInsertionPoints: (lines, publication) => { const points = {}; // Find the last publicationToPlatform.set line for (let i = lines.length - 1; i >= 0; i--) { if (lines[i].trim().startsWith('publicationToPlatform.set(')) { points.mapSet = i; break; } } return points; }, generateContent: (publication) => { const publicationName = (publication.stackAlias || publication.title.toLowerCase().replace(/\s/g, '')); return { mapSet: `publicationToPlatform.set('${publicationName}', '${publication.platform}');` }; } }, }; async function updateFile(config, publication) { const currentDir = process.cwd(); const webRepoPath = currentDir.includes('web') ? currentDir : null; if (!webRepoPath) { throw new Error('This script must be run inside the web repository.'); } const publicationName = publication.stackAlias || (publication.title ? publication.title.toLowerCase().replace(/\s/g, '') : 'default'); const resolvedPath = config.path.replace('@PUBLICATION@', publicationName); const fullPath = (0, path_1.resolve)(webRepoPath, resolvedPath); if (config.mode !== 'create' && !(0, fs_extra_1.existsSync)(fullPath)) { throw new Error(`Required file not found: ${fullPath}`); } try { if (config.mode === 'create') { // Handle file creation const generated = await config.generateContent(publication); const filePath = generated.path || config.path; const finalPath = (0, path_1.resolve)(webRepoPath, filePath); const contentToWrite = typeof generated.content === 'string' ? generated.content : Object.values(generated).join('\n'); await (0, fs_extra_1.writeFile)(finalPath, contentToWrite); (0, utils_1.logSuccess)(`Created ${filePath}`); return; } const content = await (0, fs_extra_1.readFile)(fullPath, 'utf-8'); let lines = content.split('\n'); if (config.mode === 'append') { const newContent = await config.generateContent(publication); lines.push(...Object.values(newContent)); } else if (config.mode === 'update' && config.findInsertionPoints) { const points = config.findInsertionPoints(lines, publication); const newContent = await config.generateContent(publication); Object.entries(points).forEach(([key, index]) => { if (typeof index !== 'number') return; if (key === 'domainMapEnd') { lines.splice(index, 0, newContent[key]); return; } if (key === 'publications' && points.publicationsEnd) { lines.splice(points.publicationsEnd, 0, newContent[key]); return; } if (key === 'environments' && points.environmentsEnd) { lines.splice(points.environmentsEnd, 0, newContent[key]); return; } if (key.endsWith('End')) return; if (key === 'cssList' && points.cssListEnd) { const cssListEnd = points.cssListEnd; lines.splice(cssListEnd, 0, newContent[key]); } else if (key === 'cssVarFiles' && points.cssVarFilesEnd) { const cssVarFilesEnd = points.cssVarFilesEnd; lines.splice(cssVarFilesEnd, 0, newContent[key]); } else { lines.splice(index + 1, 0, newContent[key]); } }); } await (0, fs_extra_1.writeFile)(fullPath, lines.join('\n')); (0, utils_1.logSuccess)(`Updated ${config.path}`); } catch (error) { (0, utils_1.logError)(`Failed to update ${config.path}`, error); throw error; } } async function updateFiles(publication) { for (const [name, config] of Object.entries(fileConfigs)) { await updateFile(config, publication); } }