import fs from 'fs'; import path from 'path'; import { glob } from 'glob'; import { formatPosition, Position } from '@preserves/core'; import { readSchema } from '../reader'; import chalk from 'chalk'; export interface Diagnostic { type: 'warn' | 'error'; file: string | null; detail: Error | { message: string, pos: Position | null }; }; export function computeBase(paths: string[]): string { if (paths.length === 0) { return ''; } else if (paths.length === 1) { const d = path.dirname(paths[0]); return (d === '.') ? '' : d + '/'; } else { let i = 0; while (true) { let ch: string | null = null for (const p of paths) { if (i >= p.length) return p.slice(0, i); if (ch === null) ch = p[i]; if (p[i] !== ch) return p.slice(0, i); } i++; } } } export function expandInputGlob(input: string[], base0: string | undefined) { const matches = input.flatMap(i => glob.sync(i)); const base = base0 ?? computeBase(matches); const failures: Array = []; return { base, inputFiles: matches.flatMap(inputFilePath => { if (!inputFilePath.startsWith(base)) { throw new Error(`Input filename ${inputFilePath} falls outside base ${base}`); } try { const text = fs.readFileSync(inputFilePath, 'utf-8'); const baseRelPath = inputFilePath.slice(base.length); const modulePath = baseRelPath.split('/').map(p => p.split('.')[0]).map(Symbol.for); const schema = readSchema(text, { name: inputFilePath, readInclude(includePath: string): string { return fs.readFileSync( path.resolve(path.dirname(inputFilePath), includePath), 'utf-8'); }, }); return [{ inputFilePath, text, baseRelPath, modulePath, schema }]; } catch (e) { failures.push({ type: 'error', file: inputFilePath, detail: e }); return []; } }), failures, }; } export function changeExt(p: string, newext: string): string { return p.slice(0, -path.extname(p).length) + newext; } export function formatFailures(failures: Array, traceback = false): void { for (const d of failures) { console.error( (d.type === 'error' ? chalk.redBright('[ERROR]') : chalk.yellowBright('[WARNING]')) + ' ' + chalk.blueBright(formatPosition((d.detail as any).pos ?? d.file)) + ': ' + d.detail.message + (traceback && (d.detail instanceof Error) ? '\n' + d.detail.stack : '')); } if (failures.length > 0) { console.error(); } }