UNPKG

@tsbb/typescript

Version:

TSBB is a zero-config CLI that helps you develop, test, and publish modern TypeScript project.

110 lines (109 loc) 4.21 kB
import ts from 'typescript'; import path, { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import { Log } from './log.js'; export const __filename = fileURLToPath(import.meta.url); export const __dirname = dirname(__filename); /** * * @param paths `[ 'src/index.jsx', 'test/sum.js' ]` * @returns ['src', 'test'] */ export const getRootsFolderName = (paths = []) => paths.map((item) => item.replace(/[/\\]/g, path.sep).split(path.sep)[0]); const getLnCol = (text = '', pos = 0) => { const lines = text.split('\n'); let lineNum = 1; let lineStartPos = 1; for (let i = 0; i < pos; i++) { if (text[i] === '\n') { lineNum++; lineStartPos = i + 1; } } return { ln: lineNum, col: lineStartPos, text: lines[lineNum - 1] }; }; export const getExt = (extname) => { let ext = path.extname(extname).toLocaleUpperCase().replace(/^\./, ''); ext = ext.padEnd(4, ' '); if (/^MAP/.test(ext)) { return `\x1b[34;1m${ext}\x1b[0m`; } if (/^JS/.test(ext)) { return `\x1b[33;1m${ext}\x1b[0m`; } if (/^TS/.test(ext)) { return `\x1b[36;1m${ext}\x1b[0m`; } return ext; }; export const getEmojiIcon = (fileName) => { let icon = /.d.ts$/i.test(fileName) ? '🐳' : '👉'; icon = /.js.map$/i.test(fileName) ? '🚩' : icon; return icon; }; export const writeFile = (fileName, data, writeByteOrderMark) => { const outputFile = path.join(process.cwd(), fileName); ts.sys.writeFile(outputFile, data, writeByteOrderMark); const log = new Log(); log .name() .icon(getEmojiIcon(fileName)) .success(`${getExt(fileName)}┈┈▶ \x1b[32;1m${fileName}\x1b[0m`); }; export const getSourceFile = (fileName, languageVersion, onError) => { const contents = ts.sys.readFile(fileName, 'utf8'); return ts.createSourceFile(fileName, contents || '', languageVersion); }; export const reportDiagnostic = (diagnostic) => { const log = new Log(); const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); const fileName = `\x1b[33;1m${diagnostic.file?.fileName}\x1b[0m`; const lnCol = getLnCol(diagnostic.file?.text, diagnostic.start); const codeText = lnCol.text ? `\n\n Code: \x1b[33;1m${lnCol.text}\x1b[0m` : ''; log .name() .icon('🚨') .error(`┈┈▶ ${fileName} [Ln:${lnCol.ln} Col:${lnCol.col}]`, codeText, `\n Error: ${diagnostic.code} \x1b[31;1m${message}\x1b[0m`); }; export const onWatchStatusChange = (diagnostic, newLine, options, errorCount) => { const log = new Log(); if (typeof errorCount !== 'number') { log.name().icon('🔆').success(ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')); return; } if (errorCount) { if (!diagnostic.file?.fileName) { return; } const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); const lnCol = getLnCol(diagnostic.file?.text, diagnostic.start); const fileName = `\x1b[33;1m${diagnostic.file?.fileName}\x1b[0m`; const codeText = lnCol.text ? `\n\n Code: \x1b[33;1m${lnCol.text}\x1b[0m` : ''; log .name() .icon('🚨') .error(`┈┈▶ ${fileName} [Ln:${lnCol.ln} Col:${lnCol.col}]`, codeText, `\n Error: ${diagnostic.code} \x1b[31;1m${message}\x1b[0m\n`); } else { if (!options.emitDeclarationOnly) { log.name().icon('🎉').success(diagnostic.messageText); } } }; /** * @param sourceFilePath `src/demo/index.ts` * @param rootDirsRelative `['src', 'test']` * @returns `demo/index.ts` */ export const getSourceFilePath = (sourceFilePath, rootDirsRelative) => { const rootDirsAbsolutePath = rootDirsRelative.map((dir) => path.resolve(dir)); const sourceFileAbsolutePath = path.resolve(sourceFilePath); let finalPath = sourceFileAbsolutePath; for (const rootDir of rootDirsAbsolutePath) { if (sourceFileAbsolutePath.startsWith(rootDir)) { finalPath = sourceFileAbsolutePath.slice(rootDir.length + 1); break; } } return finalPath; };