harmonyc 0.11.1 → 0.12.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.
@@ -1,5 +1,5 @@
1
1
  import { basename } from 'path';
2
- import { Arg, Word, } from "../model/model.js";
2
+ import { Arg, Response, Word, } from "../model/model.js";
3
3
  export class VitestGenerator {
4
4
  constructor(tf, sf) {
5
5
  this.tf = tf;
@@ -113,16 +113,22 @@ export class VitestGenerator {
113
113
  const f = this.featureVars.get(p.feature.name);
114
114
  const args = p.args.map((a) => a.toCode(this));
115
115
  args.push(...this.extraArgs);
116
+ if (p instanceof Response && p.parts.length === 1 && p.saveToVariable) {
117
+ return this.saveToVariable(p.saveToVariable);
118
+ }
116
119
  this.tf.print(`(context.task.meta.phrases.push(${str(p.toString())}),`);
120
+ if (p instanceof Response && p.saveToVariable) {
121
+ this.saveToVariable(p.saveToVariable, '');
122
+ }
117
123
  this.tf.print(`await ${f}.${functionName(p)}(${args.join(', ')}));`);
118
124
  }
119
125
  setVariable(action) {
120
126
  this.tf.print(`(context.task.meta.variables ??= {})[${str(action.variableName)}] = ${action.value.toCode(this)};`);
121
127
  }
122
- saveToVariable(s) {
128
+ saveToVariable(s, what = this.extraArgs[0] + ';') {
123
129
  if (this.extraArgs.length !== 1)
124
130
  return;
125
- this.tf.print(`(context.task.meta.variables ??= {})[${str(s.variableName)}] = ${this.extraArgs[0]};`);
131
+ this.tf.print(`(context.task.meta.variables ??= {})[${str(s.variableName)}] = ${what}`.trimEnd());
126
132
  }
127
133
  stringLiteral(text, { withVariables }) {
128
134
  if (withVariables && text.match(/\$\{/)) {
package/model/model.js CHANGED
@@ -256,10 +256,14 @@ export class Action extends Phrase {
256
256
  }
257
257
  }
258
258
  export class Response extends Phrase {
259
- constructor() {
260
- super(...arguments);
259
+ constructor(parts, saveToVariable) {
260
+ super([...parts, ...(saveToVariable ? [saveToVariable] : [])]);
261
+ this.saveToVariable = saveToVariable;
261
262
  this.kind = 'response';
262
263
  }
264
+ get isEmpty() {
265
+ return this.parts.length === 0 && !this.saveToVariable;
266
+ }
263
267
  toString() {
264
268
  return `=> ${super.toString()}`;
265
269
  }
@@ -288,14 +292,17 @@ export class SetVariable extends Action {
288
292
  cg.setVariable(this);
289
293
  }
290
294
  }
291
- export class SaveToVariable extends Response {
295
+ export class SaveToVariable extends Part {
292
296
  constructor(variableName) {
293
- super([new DummyKeyword(`\${${variableName}}`)]);
297
+ super();
294
298
  this.variableName = variableName;
295
299
  }
296
300
  toCode(cg) {
297
301
  cg.saveToVariable(this);
298
302
  }
303
+ toString() {
304
+ return `\${${this.variableName}}`;
305
+ }
299
306
  }
300
307
  export class Precondition extends Branch {
301
308
  constructor(state = '') {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "harmonyc",
3
3
  "description": "Harmony Code - model-driven BDD for Vitest",
4
- "version": "0.11.1",
4
+ "version": "0.12.0",
5
5
  "author": "Bernát Kalló",
6
6
  "type": "module",
7
7
  "bin": {
@@ -23,12 +23,10 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "fast-glob": "^3.3.2",
26
+ "tinyrainbow": "1",
26
27
  "typescript-parsec": "0.3.4",
27
28
  "watcher": "^2.3.1"
28
29
  },
29
- "peerDependencies": {
30
- "vitest": "^2.1.0"
31
- },
32
30
  "license": "MIT",
33
31
  "keywords": [
34
32
  "unit test",
package/parser/parser.js CHANGED
@@ -5,7 +5,7 @@ export function parse(input, production = TEST_DESIGN) {
5
5
  const tokens = lexer.parse(input);
6
6
  return expectSingleResult(expectEOF(production.parse(tokens)));
7
7
  }
8
- export const NEWLINES = list_sc(tok(T.Newline), nil()), WORDS = apply(tok(T.Words), ({ text }) => new Word(text.trimEnd().split(/\s+/).join(' '))), DOUBLE_QUOTE_STRING = alt_sc(apply(tok(T.DoubleQuoteString), ({ text }) => new StringLiteral(JSON.parse(text))), seq(tok(T.UnclosedDoubleQuoteString), fail('unclosed double-quote string'))), BACKTICK_STRING = apply(tok(T.BacktickString), ({ text }) => new CodeLiteral(text.slice(1, -1))), DOCSTRING = kright(opt_sc(NEWLINES), apply(list_sc(tok(T.MultilineString), tok(T.Newline)), (lines) => new Docstring(lines.map(({ text }) => text.slice(2)).join('\n')))), ERROR_MARK = tok(T.ErrorMark), VARIABLE = apply(tok(T.Variable), ({ text }) => text.slice(2, -1)), PART = alt_sc(WORDS, DOUBLE_QUOTE_STRING, BACKTICK_STRING, DOCSTRING), PHRASE = rep_sc(PART), ARG = alt_sc(DOUBLE_QUOTE_STRING, BACKTICK_STRING, DOCSTRING), SET_VARIABLE = apply(seq(VARIABLE, ARG), ([variable, value]) => new SetVariable(variable, value)), ACTION = alt_sc(SET_VARIABLE, apply(PHRASE, (parts) => new Action(parts))), RESPONSE = apply(PHRASE, (parts) => new Response(parts)), ERROR_RESPONSE = apply(seq(ERROR_MARK, opt_sc(alt_sc(DOUBLE_QUOTE_STRING, DOCSTRING))), ([, parts]) => new ErrorResponse(parts)), SAVE_TO_VARIABLE = apply(VARIABLE, (variable) => new SaveToVariable(variable)), ARROW = kright(opt_sc(NEWLINES), tok(T.ResponseArrow)), RESPONSE_ITEM = kright(ARROW, alt_sc(SAVE_TO_VARIABLE, ERROR_RESPONSE, RESPONSE)), STEP = apply(seq(ACTION, rep_sc(RESPONSE_ITEM)), ([action, responses]) => new Step(action, responses).setFork(true)), LABEL = apply(kleft(list_sc(PART, nil()), tok(T.Colon)), (words) => new Label(words.map((w) => w.toString()).join(' '))), SECTION = apply(LABEL, (text) => new Section(text)), BRANCH = alt_sc(SECTION, STEP), // section first, to make sure there is no colon after step
8
+ export const NEWLINES = list_sc(tok(T.Newline), nil()), WORDS = apply(tok(T.Words), ({ text }) => new Word(text.trimEnd().split(/\s+/).join(' '))), DOUBLE_QUOTE_STRING = alt_sc(apply(tok(T.DoubleQuoteString), ({ text }) => new StringLiteral(JSON.parse(text))), seq(tok(T.UnclosedDoubleQuoteString), fail('unclosed double-quote string'))), BACKTICK_STRING = apply(tok(T.BacktickString), ({ text }) => new CodeLiteral(text.slice(1, -1))), DOCSTRING = kright(opt_sc(NEWLINES), apply(list_sc(tok(T.MultilineString), tok(T.Newline)), (lines) => new Docstring(lines.map(({ text }) => text.slice(2)).join('\n')))), ERROR_MARK = tok(T.ErrorMark), VARIABLE = apply(tok(T.Variable), ({ text }) => text.slice(2, -1)), PART = alt_sc(WORDS, DOUBLE_QUOTE_STRING, BACKTICK_STRING, DOCSTRING), PHRASE = rep_sc(PART), ARG = alt_sc(DOUBLE_QUOTE_STRING, BACKTICK_STRING, DOCSTRING), SET_VARIABLE = apply(seq(VARIABLE, ARG), ([variable, value]) => new SetVariable(variable, value)), ACTION = alt_sc(SET_VARIABLE, apply(PHRASE, (parts) => new Action(parts))), RESPONSE = apply(seq(PHRASE, opt_sc(VARIABLE)), ([parts, variable]) => new Response(parts, variable !== undefined ? new SaveToVariable(variable) : undefined)), ERROR_RESPONSE = apply(seq(ERROR_MARK, opt_sc(alt_sc(DOUBLE_QUOTE_STRING, DOCSTRING))), ([, parts]) => new ErrorResponse(parts)), SAVE_TO_VARIABLE = apply(VARIABLE, (variable) => new Response([], new SaveToVariable(variable))), ARROW = kright(opt_sc(NEWLINES), tok(T.ResponseArrow)), RESPONSE_ITEM = kright(ARROW, alt_sc(SAVE_TO_VARIABLE, ERROR_RESPONSE, RESPONSE)), STEP = apply(seq(ACTION, rep_sc(RESPONSE_ITEM)), ([action, responses]) => new Step(action, responses).setFork(true)), LABEL = apply(kleft(list_sc(PART, nil()), tok(T.Colon)), (words) => new Label(words.map((w) => w.toString()).join(' '))), SECTION = apply(LABEL, (text) => new Section(text)), BRANCH = alt_sc(SECTION, STEP), // section first, to make sure there is no colon after step
9
9
  DENTS = apply(alt_sc(tok(T.Plus), tok(T.Minus)), (seqOrFork) => {
10
10
  return {
11
11
  dent: (seqOrFork.text.length - 2) / 2,