harmonyc 0.5.0 → 0.6.0-1

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/compile.js CHANGED
@@ -3,8 +3,9 @@ import { OutFile } from './outFile.js';
3
3
  import { parse } from './syntax.js';
4
4
  export function compileFeature(fileName, src) {
5
5
  const feature = parse({ fileName, src });
6
- const of = new OutFile();
6
+ const outFn = `${fileName.replace(/\.[a-z]+$/i, '')}.mjs`;
7
+ const of = new OutFile(outFn);
7
8
  const cg = new NodeTest(of);
8
9
  feature.toCode(cg);
9
- return of.value;
10
+ return of;
10
11
  }
package/compiler.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import glob from 'fast-glob';
2
2
  import { readFileSync, writeFileSync } from 'fs';
3
- import { basename } from 'path';
4
3
  import { compileFeature } from './compile.js';
5
4
  export async function compileFiles(pattern) {
6
5
  const fns = await glob(pattern);
@@ -12,8 +11,7 @@ export async function compileFiles(pattern) {
12
11
  }
13
12
  export async function compileFile(fn) {
14
13
  const src = readFileSync(fn, 'utf8').toString();
15
- const name = basename(fn).replace(/\.[a-z]+$/i, '');
16
- const outFn = `${fn.replace(/\.[a-z]+$/i, '')}.mjs`;
17
- writeFileSync(outFn, compileFeature(fn, src));
18
- return outFn;
14
+ const outFile = compileFeature(fn, src);
15
+ writeFileSync(outFile.name, outFile.value);
16
+ return outFile.name;
19
17
  }
@@ -0,0 +1,59 @@
1
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
+ };
6
+ var _FeatureContext_defs, _FeatureContext_parameterTypeRegistry;
7
+ import { CucumberExpression, ParameterTypeRegistry, } from '@cucumber/cucumber-expressions';
8
+ class Definition {
9
+ constructor(expr, fn) {
10
+ this.expr = expr;
11
+ this.fn = fn;
12
+ }
13
+ }
14
+ const features = new Map();
15
+ class FeatureContext {
16
+ constructor() {
17
+ _FeatureContext_defs.set(this, []);
18
+ _FeatureContext_parameterTypeRegistry.set(this, new ParameterTypeRegistry());
19
+ this.Action = ((s, fn) => {
20
+ if (fn) {
21
+ const expr = new CucumberExpression(s, __classPrivateFieldGet(this, _FeatureContext_parameterTypeRegistry, "f"));
22
+ const def = new Definition(expr, fn);
23
+ __classPrivateFieldGet(this, _FeatureContext_defs, "f").push(def);
24
+ return;
25
+ }
26
+ // call the action
27
+ const matches = __classPrivateFieldGet(this, _FeatureContext_defs, "f").map((def) => def.expr.match(s));
28
+ const matching = [...matches.keys()].filter((i) => matches[i]);
29
+ if (matching.length === 0) {
30
+ throw new Error(`Not defined: ${s}`);
31
+ }
32
+ if (matching.length > 1) {
33
+ throw new Error(`Ambiguous: ${s}\n${matching
34
+ .map((i) => __classPrivateFieldGet(this, _FeatureContext_defs, "f")[i].expr.source)
35
+ .join('\n')}`);
36
+ }
37
+ const match = matches[matching[0]];
38
+ const def = __classPrivateFieldGet(this, _FeatureContext_defs, "f")[matching[0]];
39
+ return Promise.resolve(def.fn(...match.map((m) => m.getValue(undefined))));
40
+ });
41
+ this.Response = this.Action;
42
+ }
43
+ }
44
+ _FeatureContext_defs = new WeakMap(), _FeatureContext_parameterTypeRegistry = new WeakMap();
45
+ export function Feature(s, fn) {
46
+ let ctx;
47
+ if (!fn) {
48
+ ctx = features.get(s);
49
+ if (!ctx)
50
+ throw new Error(`Feature not found: ${s}`);
51
+ }
52
+ else {
53
+ // redefine the feature
54
+ ctx = new FeatureContext();
55
+ features.set(s, ctx);
56
+ }
57
+ fn === null || fn === void 0 ? void 0 : fn(ctx);
58
+ return ctx;
59
+ }
@@ -1,31 +1,41 @@
1
+ import { basename } from 'path';
1
2
  export class NodeTest {
2
- constructor(outFile) {
3
- this.outFile = outFile;
3
+ constructor(of) {
4
+ this.of = of;
4
5
  this.framework = 'vitest';
6
+ this.phrases = [];
5
7
  }
6
8
  feature(feature) {
9
+ const stepsModule = './' +
10
+ basename(this.of.name.replace(/(\.(spec|test)s?)?\.[a-z]+$/i, '.steps'));
11
+ this.phrases = [];
7
12
  if (this.framework === 'vitest') {
8
- this.outFile.print(`import { test, expect } from 'vitest';`);
13
+ this.of.print(`import { test, expect } from 'vitest';`);
14
+ this.of.print(`import { Feature } from 'harmonyc/test';`);
15
+ this.of.print(`import ${JSON.stringify(stepsModule)};`);
9
16
  }
10
- this.outFile.print(feature.prelude);
17
+ this.of.print(feature.prelude);
11
18
  for (const test of feature.tests) {
12
19
  test.toCode(this);
13
20
  }
14
21
  }
15
22
  test(t) {
16
- this.outFile.print(`test('${t.name}', async () => {`);
17
- this.outFile.indent(() => {
23
+ this.of.print(`test('${t.name}', async (context) => {`);
24
+ this.of.indent(() => {
18
25
  for (const step of t.steps) {
19
26
  step.toCode(this);
20
27
  }
21
28
  });
22
- this.outFile.print('})');
23
- this.outFile.print('');
29
+ this.of.print('})');
30
+ this.of.print('');
24
31
  }
25
32
  phrase(p) {
26
- var _a;
27
- this.outFile.loc(p).print('/// ' + p.text);
28
- const code = (_a = p.definition()) !== null && _a !== void 0 ? _a : `throw 'Not defined: ' + ${JSON.stringify(p.text)};`;
29
- this.outFile.print(...code.split('\n'));
33
+ if (!this.phrases.some((x) => x.text === p.text))
34
+ this.phrases.push(p);
35
+ const feature = p.feature.name;
36
+ this.of.print(`await Feature(${JSON.stringify(feature)}).${capitalize(p.kind)}(${JSON.stringify(p.text)})`);
30
37
  }
31
38
  }
39
+ function capitalize(s) {
40
+ return s.charAt(0).toUpperCase() + s.slice(1);
41
+ }
package/outFile.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import { SourceMapGenerator } from 'source-map-js';
2
2
  export class OutFile {
3
- constructor(indentSpaces = 2) {
4
- this.indentSpaces = indentSpaces;
3
+ constructor(name) {
4
+ this.name = name;
5
5
  this.lines = [];
6
6
  this.level = 0;
7
7
  this.sm = new SourceMapGenerator();
8
+ this.indentSpaces = 2;
8
9
  }
9
10
  indent(fn) {
10
11
  this.level++;
package/package.json CHANGED
@@ -1,12 +1,18 @@
1
1
  {
2
2
  "name": "harmonyc",
3
3
  "description": "Harmony Code - model-driven BDD for Vitest",
4
- "version": "0.5.0",
4
+ "version": "0.6.0-1",
5
5
  "author": "Bernát Kalló",
6
6
  "type": "module",
7
7
  "bin": {
8
8
  "harmonyc": "./cli.js"
9
9
  },
10
+ "exports": {
11
+ "./test": {
12
+ "types": "./test.d.ts",
13
+ "default": "./dist/js_api/js_api.js"
14
+ }
15
+ },
10
16
  "homepage": "https://github.com/harmony-ac/code#readme",
11
17
  "repository": {
12
18
  "type": "git",
package/test.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ type FeatureContext = {
2
+ Action(s: string): Promise<void>
3
+ Action(s: string, fn: Function): void
4
+ Response(s: string): Promise<void>
5
+ Response(s: string, fn: Function): void
6
+ }
7
+ export function Feature(name: string, fn: (ctx: FeatureContext) => void): void