harmonyc 0.16.4 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Harmony Code
2
2
 
3
- A test design & BDD tool that helps you separate the _what_ to test from the _how_ to automate it. You write test cases in a simple easy-to-read format, and then automate them with Vitest (and soon with other frameworks and languages).
3
+ A test design & BDD tool that helps you separate _what_ you test and _how_ you automate it. You write test cases in a simple easy-to-read format, and then automate them with Vitest.
4
4
 
5
5
  ## Setup
6
6
 
@@ -10,23 +10,24 @@ You need to have Node.js installed. Then you can install Harmony Code in your pr
10
10
  npm install harmonyc
11
11
  ```
12
12
 
13
- Then add it to your `vitest.config.js` or `vite.config.js` file, and specify which folder to watch for `.harmony` files:
13
+ Then add it as a plugin to your `vitest.config.js` or `vite.config.js` file, and make sure to include your `.harmony` files:
14
14
 
15
15
  ```js
16
16
  import harmony from 'harmonyc/vitest'
17
17
 
18
18
  export default {
19
- plugins: [harmony({ watchDir: 'src' })],
19
+ plugins: [harmony()],
20
+ include: ['src/**/*.harmony'],
20
21
  }
21
22
  ```
22
23
 
23
- You can run it manually for all `.harmony` files in your `src` folder:
24
+ This will run .harmony files in vitest.
24
25
 
25
- ```bash
26
- harmonyc src/**/*.harmony
27
- ```
26
+ ## VSCode plugin
27
+
28
+ Harmony Code has a [VSCode plugin](https://marketplace.visualstudio.com/items?itemName=harmony-ac.harmony-code) that supports syntax highlighting.
28
29
 
29
- This will generate `.test.mjs` files next to the `.harmony` files, and generate empty definition files for you.
30
+ Harmony Code is compatible with Vitest's VSCode plugin, so you can run and debug tests from the editor.
30
31
 
31
32
  ## Syntax
32
33
 
@@ -77,12 +78,12 @@ becomes
77
78
 
78
79
  ```javascript
79
80
  test('T1 - strings', async () => {
80
- const P = new Phrases();
81
- await P.When_hello_("John");
81
+ const P = new Phrases()
82
+ await P.When_hello_('John')
82
83
  })
83
84
  test('T2 - code fragment', async () => {
84
- const P = new Phrases();
85
- await P.When_greet__times(3);
85
+ const P = new Phrases()
86
+ await P.When_greet__times(3)
86
87
  })
87
88
  ```
88
89
 
@@ -136,7 +137,6 @@ test('T2 - store result in variable', (context) => {
136
137
  })
137
138
  ```
138
139
 
139
-
140
140
  ## License
141
141
 
142
142
  MIT
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "harmonyc",
3
3
  "description": "Harmony Code - model-driven BDD for Vitest",
4
- "version": "0.16.4",
4
+ "version": "0.18.0",
5
5
  "author": "Bernát Kalló",
6
6
  "type": "module",
7
7
  "bin": {
8
8
  "harmonyc": "./cli.js"
9
9
  },
10
+ "files": [
11
+ "."
12
+ ],
10
13
  "exports": {
11
14
  "./vitest": {
12
15
  "types": "./vitest/index.d.ts",
@@ -24,7 +27,9 @@
24
27
  "dependencies": {
25
28
  "fast-glob": "^3.3.2",
26
29
  "tinyrainbow": "1",
27
- "typescript-parsec": "0.3.4",
30
+ "typescript-parsec": "0.3.4"
31
+ },
32
+ "optionalDependencies": {
28
33
  "watcher": "^2.3.1"
29
34
  },
30
35
  "license": "MIT",
package/cli/cli.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
package/cli/cli.js DELETED
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env node
2
- import { compileFiles } from "../compiler/compiler.js";
3
- import { parseArgs } from 'node:util';
4
- import { watchFiles } from "./watch.js";
5
- import { run, runWatch } from "./run.js";
6
- const args = parseArgs({
7
- options: {
8
- help: { type: 'boolean' },
9
- watch: { type: 'boolean', short: 'w' },
10
- run: { type: 'boolean', short: 'r' },
11
- },
12
- allowPositionals: true,
13
- });
14
- if (args.positionals.length === 0 || args.values.help) {
15
- console.error('Usage: harmonyc <input files glob pattern>');
16
- process.exit(1);
17
- }
18
- ;
19
- (async () => {
20
- if (args.values.watch) {
21
- const outFns = await watchFiles(args.positionals);
22
- if (args.values.run) {
23
- runWatch(outFns);
24
- }
25
- }
26
- else {
27
- const { outFns } = await compileFiles(args.positionals);
28
- if (args.values.run) {
29
- run(outFns);
30
- }
31
- }
32
- })();
package/cli/run.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export declare function run(patterns: string[]): void;
2
- export declare function runWatch(patterns: string[]): void;
package/cli/run.js DELETED
@@ -1,21 +0,0 @@
1
- import { exec, spawn } from 'child_process';
2
- function runCommand(patterns) {
3
- return `npx vitest run ${args(patterns)}`;
4
- }
5
- function runWatchCommand(patterns) {
6
- return `npx vitest ${args(patterns)}`;
7
- }
8
- function args(patterns) {
9
- return patterns.map((s) => JSON.stringify(s)).join(' ');
10
- }
11
- export function run(patterns) {
12
- var _a, _b;
13
- const cmd = runCommand(patterns);
14
- const p = exec(cmd, { cwd: process.cwd() });
15
- (_a = p.stdout) === null || _a === void 0 ? void 0 : _a.pipe(process.stdout);
16
- (_b = p.stderr) === null || _b === void 0 ? void 0 : _b.pipe(process.stderr);
17
- }
18
- export function runWatch(patterns) {
19
- const cmd = runWatchCommand(patterns);
20
- spawn(cmd, { cwd: process.cwd(), stdio: 'inherit', shell: true });
21
- }
package/cli/watch.d.ts DELETED
@@ -1 +0,0 @@
1
- export declare function watchFiles(patterns: string[]): Promise<string[]>;
package/cli/watch.js DELETED
@@ -1,35 +0,0 @@
1
- import Watcher from 'watcher';
2
- import { compileFile, compileFiles } from "../compiler/compiler.js";
3
- export async function watchFiles(patterns) {
4
- const { fns, outFns } = await compileFiles(patterns);
5
- for (const file of fns) {
6
- const watcher = new Watcher(file, { debounce: 20, ignoreInitial: true });
7
- watcher.on('all', async () => {
8
- var _a;
9
- try {
10
- await compileFile(file);
11
- }
12
- catch (e) {
13
- process.stdout.write(`\n`);
14
- console.log((_a = e.message) !== null && _a !== void 0 ? _a : e);
15
- process.stdout.write(`\n`);
16
- }
17
- logger.log(`Compiled ${file}`);
18
- });
19
- }
20
- return outFns;
21
- }
22
- const logger = {
23
- last: '',
24
- n: 0,
25
- log(msg) {
26
- if (msg === this.last) {
27
- process.stdout.write(`\r${msg} ${++this.n}x`);
28
- }
29
- else {
30
- process.stdout.write(`\r${msg}`);
31
- this.last = msg;
32
- this.n = 1;
33
- }
34
- },
35
- };
@@ -1,31 +0,0 @@
1
- import { Action, CodeGenerator, ErrorResponse, Feature, Phrase, Response, SaveToVariable, SetVariable, Test, TestGroup } from '../model/model.ts';
2
- import { OutFile } from './outFile.ts';
3
- export declare class VitestGenerator implements CodeGenerator {
4
- private tf;
5
- private sf;
6
- static error(message: string, stack: string): string;
7
- framework: string;
8
- phraseFns: Map<string, Phrase>;
9
- currentFeatureName: string;
10
- constructor(tf: OutFile, sf: OutFile);
11
- feature(feature: Feature): void;
12
- testGroup(g: TestGroup): void;
13
- featureVars: Map<string, string>;
14
- resultCount: number;
15
- test(t: Test): void;
16
- errorStep(action: Action, errorResponse: ErrorResponse): void;
17
- extraArgs: string[];
18
- step(action: Action, responses: Response[]): void;
19
- private declareFeatureVariables;
20
- phrase(p: Phrase): void;
21
- setVariable(action: SetVariable): void;
22
- saveToVariable(s: SaveToVariable, what?: string): void;
23
- stringLiteral(text: string, { withVariables }: {
24
- withVariables: boolean;
25
- }): string;
26
- codeLiteral(src: string): string;
27
- private paramName;
28
- stringParamDeclaration(index: number): string;
29
- variantParamDeclaration(index: number): string;
30
- }
31
- export declare function functionName(phrase: Phrase): string;
@@ -1,212 +0,0 @@
1
- import { basename } from 'path';
2
- import { Arg, Response, Word, } from "../model/model.js";
3
- export class VitestGenerator {
4
- static error(message, stack) {
5
- return `const e = new SyntaxError(${str(message)});
6
- e.stack = undefined;
7
- throw e;
8
- ${stack ? `/* ${stack} */` : ''}`;
9
- }
10
- constructor(tf, sf) {
11
- this.tf = tf;
12
- this.sf = sf;
13
- this.framework = 'vitest';
14
- this.phraseFns = new Map();
15
- this.currentFeatureName = '';
16
- this.resultCount = 0;
17
- this.extraArgs = [];
18
- }
19
- feature(feature) {
20
- const phrasesModule = './' + basename(this.sf.name.replace(/.(js|ts)$/, ''));
21
- const fn = (this.currentFeatureName = pascalCase(feature.name));
22
- this.phraseFns = new Map();
23
- if (this.framework === 'vitest') {
24
- this.tf.print(`import { describe, test, expect } from "vitest";`);
25
- }
26
- if (feature.tests.length === 0) {
27
- this.tf.print('');
28
- this.tf.print(`describe.todo(${str(feature.name)});`);
29
- return;
30
- }
31
- this.tf.print(`import ${fn}Phrases from ${str(phrasesModule)};`);
32
- this.tf.print(``);
33
- for (const item of feature.testGroups) {
34
- item.toCode(this);
35
- }
36
- this.sf.print(`export default class ${pascalCase(feature.name)}Phrases {`);
37
- this.sf.indent(() => {
38
- for (const ph of this.phraseFns.keys()) {
39
- const p = this.phraseFns.get(ph);
40
- const params = p.args.map((a, i) => a.toDeclaration(this, i)).join(', ');
41
- this.sf.print(`async ${ph}(${params}) {`);
42
- this.sf.indent(() => {
43
- this.sf.print(`throw new Error(${str(`Pending: ${ph}`)});`);
44
- });
45
- this.sf.print(`}`);
46
- }
47
- });
48
- this.sf.print(`};`);
49
- }
50
- testGroup(g) {
51
- this.tf.print(`describe(${str(g.name)}, () => {`);
52
- this.tf.indent(() => {
53
- for (const item of g.items) {
54
- item.toCode(this);
55
- }
56
- });
57
- this.tf.print('});');
58
- }
59
- test(t) {
60
- this.resultCount = 0;
61
- this.featureVars = new Map();
62
- // avoid shadowing this import name
63
- this.featureVars.set(new Object(), this.currentFeatureName);
64
- this.tf.print(`test(${str(t.name)}, async (context) => {`);
65
- this.tf.indent(() => {
66
- this.tf.print(`context.task.meta.phrases ??= [];`);
67
- for (const step of t.steps) {
68
- step.toCode(this);
69
- }
70
- });
71
- this.tf.print('});');
72
- }
73
- errorStep(action, errorResponse) {
74
- this.declareFeatureVariables([action]);
75
- this.tf.print(`await expect(async () => {`);
76
- this.tf.indent(() => {
77
- action.toCode(this);
78
- this.tf.print(`context.task.meta.phrases.push(${str(errorResponse.toSingleLineString())});`);
79
- });
80
- this.tf.print(`}).rejects.toThrow(${(errorResponse === null || errorResponse === void 0 ? void 0 : errorResponse.message) !== undefined
81
- ? str(errorResponse.message.text)
82
- : ''});`);
83
- }
84
- step(action, responses) {
85
- this.declareFeatureVariables([action, ...responses]);
86
- if (responses.length === 0) {
87
- action.toCode(this);
88
- return;
89
- }
90
- if (action.isEmpty) {
91
- for (const response of responses) {
92
- response.toCode(this);
93
- }
94
- return;
95
- }
96
- const res = `r${this.resultCount++ || ''}`;
97
- this.tf.print(`const ${res} =`);
98
- this.tf.indent(() => {
99
- action.toCode(this);
100
- try {
101
- this.extraArgs = [res];
102
- for (const response of responses) {
103
- response.toCode(this);
104
- }
105
- }
106
- finally {
107
- this.extraArgs = [];
108
- }
109
- });
110
- }
111
- declareFeatureVariables(phrases) {
112
- for (const p of phrases) {
113
- const feature = p.feature.name;
114
- let f = this.featureVars.get(feature);
115
- if (!f) {
116
- f = toId(feature, abbrev, this.featureVars);
117
- this.tf.print(`const ${f} = new ${pascalCase(feature)}Phrases(context);`);
118
- }
119
- }
120
- }
121
- phrase(p) {
122
- const phrasefn = functionName(p);
123
- if (!this.phraseFns.has(phrasefn))
124
- this.phraseFns.set(phrasefn, p);
125
- const f = this.featureVars.get(p.feature.name);
126
- const args = p.args.map((a) => a.toCode(this));
127
- args.push(...this.extraArgs);
128
- if (p instanceof Response && p.parts.length === 1 && p.saveToVariable) {
129
- return this.saveToVariable(p.saveToVariable);
130
- }
131
- this.tf.print(`(context.task.meta.phrases.push(${str(p.toString())}),`);
132
- if (p instanceof Response && p.saveToVariable) {
133
- this.saveToVariable(p.saveToVariable, '');
134
- }
135
- this.tf.print(`await ${f}.${functionName(p)}(${args.join(', ')}));`);
136
- }
137
- setVariable(action) {
138
- this.tf.print(`(context.task.meta.variables ??= {})[${str(action.variableName)}] = ${action.value.toCode(this)};`);
139
- }
140
- saveToVariable(s, what = this.extraArgs[0] + ';') {
141
- this.tf.print(`(context.task.meta.variables ??= {})[${str(s.variableName)}] = ${what}`.trimEnd());
142
- }
143
- stringLiteral(text, { withVariables }) {
144
- if (withVariables && text.match(/\$\{/)) {
145
- return templateStr(text).replace(/\\\$\{([^\s}]+)\}/g, (_, x) => `\${context.task.meta.variables?.[${str(x)}]}`);
146
- }
147
- return str(text);
148
- }
149
- codeLiteral(src) {
150
- return src.replace(/\$\{([^\s}]+)\}/g, (_, x) => `context.task.meta.variables?.[${str(x)}]`);
151
- }
152
- paramName(index) {
153
- return 'xyz'.charAt(index) || `a${index + 1}`;
154
- }
155
- stringParamDeclaration(index) {
156
- return `${this.paramName(index)}: string`;
157
- }
158
- variantParamDeclaration(index) {
159
- return `${this.paramName(index)}: any`;
160
- }
161
- }
162
- function str(s) {
163
- if (s.includes('\n'))
164
- return '\n' + templateStr(s);
165
- let r = JSON.stringify(s);
166
- return r;
167
- }
168
- function templateStr(s) {
169
- return '`' + s.replace(/([`$\\])/g, '\\$1') + '`';
170
- }
171
- function capitalize(s) {
172
- return s.charAt(0).toUpperCase() + s.slice(1);
173
- }
174
- function toId(s, transform, previous) {
175
- if (previous.has(s))
176
- return previous.get(s);
177
- let base = transform(s);
178
- let id = base;
179
- if ([...previous.values()].includes(id)) {
180
- let i = 1;
181
- while ([...previous.values()].includes(id + i))
182
- i++;
183
- id = base + i;
184
- }
185
- previous.set(s, id);
186
- return id;
187
- }
188
- function words(s) {
189
- return s.split(/[^0-9\p{L}]+/gu);
190
- }
191
- function pascalCase(s) {
192
- return words(s).map(capitalize).join('');
193
- }
194
- function underscore(s) {
195
- return words(s).join('_');
196
- }
197
- function abbrev(s) {
198
- return words(s)
199
- .map((x) => x.charAt(0).toUpperCase())
200
- .join('');
201
- }
202
- export function functionName(phrase) {
203
- const { kind } = phrase;
204
- return ((kind === 'response' ? 'Then_' : 'When_') +
205
- (phrase.parts
206
- .flatMap((c) => c instanceof Word
207
- ? words(c.text).filter((x) => x)
208
- : c instanceof Arg
209
- ? ['']
210
- : [])
211
- .join('_') || ''));
212
- }
@@ -1,17 +0,0 @@
1
- import { Location } from '../model/model.ts';
2
- import { SourceMapGenerator } from 'source-map-js';
3
- export declare class OutFile {
4
- name: string;
5
- lines: string[];
6
- level: number;
7
- sm: SourceMapGenerator;
8
- indentSpaces: number;
9
- private currentLoc;
10
- constructor(name: string);
11
- indent(fn: () => void): void;
12
- print(...lines: string[]): this;
13
- loc({ location }: {
14
- location?: Location;
15
- }): this;
16
- get value(): string;
17
- }
@@ -1,51 +0,0 @@
1
- import { SourceMapGenerator } from 'source-map-js';
2
- export class OutFile {
3
- constructor(name) {
4
- this.name = name;
5
- this.lines = [];
6
- this.level = 0;
7
- this.sm = new SourceMapGenerator();
8
- this.indentSpaces = 2;
9
- }
10
- indent(fn) {
11
- this.level++;
12
- try {
13
- fn();
14
- }
15
- finally {
16
- this.level--;
17
- }
18
- }
19
- print(...lines) {
20
- const l = this.lines.length;
21
- this.lines.push(...lines.map((line) => ' '.repeat(this.level * this.indentSpaces) + line));
22
- if (this.currentLoc)
23
- for (const i of lines.keys()) {
24
- this.sm.addMapping({
25
- source: this.currentLoc.fileName,
26
- original: {
27
- line: this.currentLoc.line,
28
- column: this.currentLoc.column,
29
- },
30
- generated: {
31
- line: l + i,
32
- column: this.level * this.indentSpaces,
33
- },
34
- });
35
- }
36
- return this;
37
- }
38
- loc({ location }) {
39
- this.currentLoc = location;
40
- return this;
41
- }
42
- get value() {
43
- let res = this.lines.join('\n');
44
- if (this.currentLoc) {
45
- res +=
46
- `\n\n//# sour` + // not for this file ;)
47
- `ceMappingURL=data:application/json,${encodeURIComponent(this.sm.toString())}`;
48
- }
49
- return res;
50
- }
51
- }
@@ -1,11 +0,0 @@
1
- export declare class TestPhrases {
2
- private context;
3
- constructor(context: any);
4
- When_goodbye(): void;
5
- When_hello(): string;
6
- When_greet_(name: string): void;
7
- Then__is_(x: string, y: string): Promise<void>;
8
- Then_last_char(s: string): string;
9
- Then_last_char_of_greeting(): any;
10
- Then_(s: string, r: string): void;
11
- }
@@ -1,27 +0,0 @@
1
- import { expect } from 'vitest';
2
- export class TestPhrases {
3
- constructor(context) {
4
- this.context = context;
5
- }
6
- When_goodbye() {
7
- throw new Error('Goodbye, World!');
8
- }
9
- When_hello() {
10
- return (this.context.task.meta.greeting = 'Hello!');
11
- }
12
- When_greet_(name) {
13
- this.context.task.meta.greeting = `Hello, ${name}!`;
14
- }
15
- async Then__is_(x, y) {
16
- expect(x).toBe(y);
17
- }
18
- Then_last_char(s) {
19
- return s.slice(-1);
20
- }
21
- Then_last_char_of_greeting() {
22
- return this.context.task.meta.greeting.slice(-1);
23
- }
24
- Then_(s, r) {
25
- expect(s).toBe(r);
26
- }
27
- }
@@ -1,9 +0,0 @@
1
- import { OutFile } from '../code_generator/outFile.ts';
2
- export interface CompiledFeature {
3
- name: string;
4
- code: Record<string, string>;
5
- }
6
- export declare function compileFeature(fileName: string, src: string): {
7
- outFile: OutFile;
8
- phrasesFile: OutFile;
9
- };
@@ -1,32 +0,0 @@
1
- import { VitestGenerator } from "../code_generator/VitestGenerator.js";
2
- import { OutFile } from "../code_generator/outFile.js";
3
- import { parse } from "../parser/parser.js";
4
- import { base, phrasesFileName, testFileName } from "../filenames/filenames.js";
5
- import { Feature } from "../model/model.js";
6
- import { basename } from 'node:path';
7
- import { autoLabel } from "../optimizations/autoLabel/autoLabel.js";
8
- export function compileFeature(fileName, src) {
9
- const feature = new Feature(basename(base(fileName)));
10
- try {
11
- feature.root = parse(src);
12
- }
13
- catch (e) {
14
- if (e.pos && e.errorMessage) {
15
- e.message =
16
- e.stack = `Error in ${fileName}:${e.pos.rowBegin}:${e.pos.columnBegin}\n${e.errorMessage}`;
17
- }
18
- else {
19
- e.stack = `Error in ${fileName}\n${e.stack}`;
20
- }
21
- throw e;
22
- }
23
- feature.root.setFeature(feature);
24
- autoLabel(feature.root);
25
- const testFn = testFileName(fileName);
26
- const testFile = new OutFile(testFn);
27
- const phrasesFn = phrasesFileName(fileName);
28
- const phrasesFile = new OutFile(phrasesFn);
29
- const cg = new VitestGenerator(testFile, phrasesFile);
30
- feature.toCode(cg);
31
- return { outFile: testFile, phrasesFile };
32
- }
@@ -1,9 +0,0 @@
1
- export declare function compileFiles(pattern: string | string[]): Promise<{
2
- fns: string[];
3
- outFns: string[];
4
- }>;
5
- export declare function compileFile(fn: string): Promise<{
6
- phrasesFileAction: string;
7
- outFile: import("../code_generator/outFile.ts").OutFile;
8
- phrasesFile: import("../code_generator/outFile.ts").OutFile;
9
- } | undefined>;
@@ -1,48 +0,0 @@
1
- import glob from 'fast-glob';
2
- import { existsSync, readFileSync, writeFileSync } from 'fs';
3
- import { resolve } from 'path';
4
- import { compileFeature } from "./compile.js";
5
- import { testFileName } from "../filenames/filenames.js";
6
- import { VitestGenerator } from "../code_generator/VitestGenerator.js";
7
- export async function compileFiles(pattern) {
8
- var _a;
9
- const fns = await glob(pattern);
10
- if (!fns.length)
11
- throw new Error(`No files found for pattern: ${String(pattern)}`);
12
- const results = await Promise.allSettled(fns.map((fn) => compileFile(fn)));
13
- const compiled = results.flatMap((r) => r.status === 'fulfilled' ? [r.value] : []);
14
- const errored = results.flatMap((r) => r.status === 'rejected' && r.reason ? [r.reason] : []);
15
- for (const error of errored) {
16
- console.error((_a = error.message) !== null && _a !== void 0 ? _a : error);
17
- }
18
- console.log(`Compiled ${compiled.length} file${compiled.length === 1 ? '' : 's'}.`);
19
- const features = compiled.filter((f) => f !== undefined);
20
- const generated = features.filter((f) => f.phrasesFileAction === 'generated');
21
- if (generated.length) {
22
- console.log(`Generated ${generated.length} phrases file${generated.length === 1 ? '' : 's'}.`);
23
- }
24
- return { fns, outFns: features.map((f) => f.outFile.name) };
25
- }
26
- export async function compileFile(fn) {
27
- var _a;
28
- fn = resolve(fn);
29
- const src = readFileSync(fn, 'utf8')
30
- .toString()
31
- .replace(/\r\n/g, '\n')
32
- .replace(/\r/g, '\n');
33
- try {
34
- const { outFile, phrasesFile } = compileFeature(fn, src);
35
- writeFileSync(outFile.name, outFile.value);
36
- let phrasesFileAction = 'ignored';
37
- if (!existsSync(phrasesFile.name)) {
38
- phrasesFileAction = 'generated';
39
- writeFileSync(phrasesFile.name, phrasesFile.value);
40
- }
41
- return { phrasesFileAction, outFile, phrasesFile };
42
- }
43
- catch (e) {
44
- const outFileName = testFileName(fn);
45
- writeFileSync(outFileName, VitestGenerator.error((_a = e.message) !== null && _a !== void 0 ? _a : `${e}`, e.stack));
46
- return undefined;
47
- }
48
- }
@@ -1,3 +0,0 @@
1
- export declare function base(fn: string): string;
2
- export declare function testFileName(fn: string): string;
3
- export declare function phrasesFileName(fn: string): string;
@@ -1,17 +0,0 @@
1
- import glob from 'fast-glob';
2
- const { globSync, convertPathToPattern } = glob;
3
- export function base(fn) {
4
- return fn.replace(/\.harmony(\.\w+)?$/i, '');
5
- }
6
- export function testFileName(fn) {
7
- return base(fn) + '.test.mjs';
8
- }
9
- export function phrasesFileName(fn) {
10
- const baseFn = base(fn);
11
- const pattern = convertPathToPattern(baseFn);
12
- const existing = globSync(`${pattern}.phrases.{tsx,jsx,ts,js}`);
13
- if (existing.length) {
14
- return existing.sort().at(-1);
15
- }
16
- return `${baseFn}.phrases.ts`;
17
- }