harmonyc 0.11.2 → 0.12.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.
@@ -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;
@@ -60,14 +60,15 @@ export class VitestGenerator {
60
60
  this.tf.print('});');
61
61
  }
62
62
  errorStep(action, errorResponse) {
63
- var _a;
64
63
  this.declareFeatureVariables([action]);
65
64
  this.tf.print(`context.task.meta.phrases.push(${str(errorResponse.toSingleLineString())});`);
66
65
  this.tf.print(`await expect(async () => {`);
67
66
  this.tf.indent(() => {
68
67
  action.toCode(this);
69
68
  });
70
- this.tf.print(`}).rejects.toThrow(${(_a = errorResponse === null || errorResponse === void 0 ? void 0 : errorResponse.toCode(this)) !== null && _a !== void 0 ? _a : ''});`);
69
+ this.tf.print(`}).rejects.toThrow(${(errorResponse === null || errorResponse === void 0 ? void 0 : errorResponse.message) !== undefined
70
+ ? str(errorResponse.message.text)
71
+ : ''});`);
71
72
  }
72
73
  step(action, responses) {
73
74
  this.declareFeatureVariables([action, ...responses]);
@@ -113,16 +114,22 @@ export class VitestGenerator {
113
114
  const f = this.featureVars.get(p.feature.name);
114
115
  const args = p.args.map((a) => a.toCode(this));
115
116
  args.push(...this.extraArgs);
117
+ if (p instanceof Response && p.parts.length === 1 && p.saveToVariable) {
118
+ return this.saveToVariable(p.saveToVariable);
119
+ }
116
120
  this.tf.print(`(context.task.meta.phrases.push(${str(p.toString())}),`);
121
+ if (p instanceof Response && p.saveToVariable) {
122
+ this.saveToVariable(p.saveToVariable, '');
123
+ }
117
124
  this.tf.print(`await ${f}.${functionName(p)}(${args.join(', ')}));`);
118
125
  }
119
126
  setVariable(action) {
120
127
  this.tf.print(`(context.task.meta.variables ??= {})[${str(action.variableName)}] = ${action.value.toCode(this)};`);
121
128
  }
122
- saveToVariable(s) {
129
+ saveToVariable(s, what = this.extraArgs[0] + ';') {
123
130
  if (this.extraArgs.length !== 1)
124
131
  return;
125
- this.tf.print(`(context.task.meta.variables ??= {})[${str(s.variableName)}] = ${this.extraArgs[0]};`);
132
+ this.tf.print(`(context.task.meta.variables ??= {})[${str(s.variableName)}] = ${what}`.trimEnd());
126
133
  }
127
134
  stringLiteral(text, { withVariables }) {
128
135
  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
  }
@@ -277,6 +281,9 @@ export class ErrorResponse extends Response {
277
281
  super(message ? [new DummyKeyword('!!'), message] : [new DummyKeyword('!!')]);
278
282
  this.message = message;
279
283
  }
284
+ toCode(cg) {
285
+ cg.errorStep;
286
+ }
280
287
  }
281
288
  export class SetVariable extends Action {
282
289
  constructor(variableName, value) {
@@ -288,14 +295,17 @@ export class SetVariable extends Action {
288
295
  cg.setVariable(this);
289
296
  }
290
297
  }
291
- export class SaveToVariable extends Response {
298
+ export class SaveToVariable extends Part {
292
299
  constructor(variableName) {
293
- super([new DummyKeyword(`\${${variableName}}`)]);
300
+ super();
294
301
  this.variableName = variableName;
295
302
  }
296
303
  toCode(cg) {
297
304
  cg.saveToVariable(this);
298
305
  }
306
+ toString() {
307
+ return `\${${this.variableName}}`;
308
+ }
299
309
  }
300
310
  export class Precondition extends Branch {
301
311
  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.2",
4
+ "version": "0.12.1",
5
5
  "author": "Bernát Kalló",
6
6
  "type": "module",
7
7
  "bin": {
package/parser/lexer.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { TokenError } from 'typescript-parsec';
2
- import rules from "./lexer_rules.js";
3
- export { T } from "./lexer_rules.js";
2
+ import rules from './lexer_rules.js';
3
+ export { T } from './lexer_rules.js';
4
4
  // based on https://github.com/microsoft/ts-parsec/blob/3350fcb/packages/ts-parsec/src/Lexer.ts
5
5
  /*
6
6
  MIT License
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,