UNPKG

harmonyc

Version:

Harmony Code - model-driven BDD for Vitest

108 lines (107 loc) 3.74 kB
import { readFile, writeFile } from 'fs/promises'; import c from 'tinyrainbow'; import { Project } from 'ts-morph'; import { compileFeature } from "../compiler/compile.js"; import { preprocess } from "../compiler/compiler.js"; import { PhrasesAssistant } from "../phrases_assistant/phrases_assistant.js"; const DEFAULT_OPTIONS = { autoEditPhrases: true, }; export default function harmonyPlugin(opts = {}) { const options = { ...DEFAULT_OPTIONS, ...opts }; const project = new Project(); return { name: 'harmony', resolveId(id) { if (id.endsWith('.harmony')) { return id; } }, transform(code, id) { if (!id.endsWith('.harmony')) return null; code = preprocess(code); const { outFile, phraseMethods, featureClassName } = compileFeature(id, code, opts); if (options.autoEditPhrases) { void updatePhrasesFile(project, id, phraseMethods, featureClassName); } return { code: outFile.valueWithoutSourceMap, map: outFile.sourceMap, }; }, config(config) { var _a, _b; var _c; (_a = config.test) !== null && _a !== void 0 ? _a : (config.test = {}); (_b = (_c = config.test).reporters) !== null && _b !== void 0 ? _b : (_c.reporters = ['default']); if (!Array.isArray(config.test.reporters)) { config.test.reporters = [config.test.reporters]; } config.test.reporters.splice(0, 0, new HarmonyReporter()); }, }; } class HarmonyReporter { onInit(ctx) { this.ctx = ctx; } onCollected(files) { this.files = files; } onTaskUpdate(packs) { if (this.files) for (const file of this.files) addPhrases(file); } onFinished(files, errors) { for (const file of files) addPhrases(file); } } function addPhrases(task, depth = 2) { var _a, _b; if ('tasks' in task) { for (const child of task.tasks) addPhrases(child, depth + 1); } else if (task.type === 'test' && ((_a = task.result) === null || _a === void 0 ? void 0 : _a.state) === 'fail' && ((_b = task.meta) === null || _b === void 0 ? void 0 : _b.hasOwnProperty('phrases')) && task.meta.phrases.length > 0) { const x = task; x.name += '\n' + task.meta .phrases.map((step, i, a) => { const indent = ' '.repeat(depth); const failed = i === a.length - 1; const figure = failed ? c.red('×') : c.green('✓'); return `${indent}${figure} ${step}`; }) .join('\n'); delete task.meta.phrases; // to make sure not to add them again } } async function updatePhrasesFile(project, id, phraseMethods, featureClassName) { try { const phrasesFile = id.replace(/\.harmony$/, '.phrases.ts'); let phrasesFileContent = ''; try { phrasesFileContent = await readFile(phrasesFile, 'utf-8'); } catch { // File doesn't exist } const pa = new PhrasesAssistant(project, phrasesFile, featureClassName); pa.ensureMethods(phraseMethods); const newContent = pa.toCode(); if (newContent === phrasesFileContent) { return; // No changes needed } await writeFile(phrasesFile, newContent, 'utf-8'); } catch (e) { console.error('Error updating phrases file:', e); } }