diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 561d1c2a..cc38fbae 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -4,24 +4,27 @@ on: push: branches: - main + permissions: contents: write jobs: deploy_pages: runs-on: ubuntu-latest - steps: - name: Checkout 🛎️ uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '18' cache: 'pnpm' + - uses: pnpm/action-setup@v2 - name: Install pnpm - with: - version: 8 + name: Install pnpm + with: + version: 8 + - run: | pnpm install pnpm docs diff --git a/jest.config.ts b/jest.config.ts index 0af24189..ade69b28 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -1,4 +1,4 @@ -import { type JestConfigWithTsJest } from 'ts-jest'; +import type { JestConfigWithTsJest } from 'ts-jest'; export default { transform: { '^.+\\.ts$': ['ts-jest', { useESM: true }] }, diff --git a/pkg/fs/lexer.test.ts b/pkg/fs/lexer.test.ts index 00588dfb..59e15979 100644 --- a/pkg/fs/lexer.test.ts +++ b/pkg/fs/lexer.test.ts @@ -3,7 +3,7 @@ import { ThenI, SaveThe, IntoTheFile } from './tokens'; import { Identifier } from '@slangroom/shared/tokens'; -test('that lexing works', async () => { +test('lexing works', async () => { // Given I have a contract with filesystem statements in it const contract = `Rule unknown ignore Given I have a 'string' named 'stringToWrite' diff --git a/pkg/fs/parser.ts b/pkg/fs/parser.ts index a4ca2bbf..32e0492e 100644 --- a/pkg/fs/parser.ts +++ b/pkg/fs/parser.ts @@ -1,7 +1,7 @@ import { IntoTheFile, SaveThe, ThenI, vocab } from './tokens'; import { lex } from './lexer'; -import { CstParser, IToken } from '@slangroom/deps/chevrotain'; +import { CstParser, type IToken } from '@slangroom/deps/chevrotain'; import { Identifier } from '@slangroom/shared/tokens'; import { ZenroomParams } from '@slangroom/shared/zenroom'; @@ -19,7 +19,7 @@ class Parser extends CstParser { this.performSelfAnalysis(); } - public fileOverrideStatement = this.RULE('fileOverrideStatement', () => { + fileOverrideStatement = this.RULE('fileOverrideStatement', () => { this.CONSUME(ThenI); this.CONSUME(SaveThe); this.CONSUME(Identifier, { LABEL: 'content' }); diff --git a/pkg/fs/tokens.ts b/pkg/fs/tokens.ts index 4d174654..f4292de7 100644 --- a/pkg/fs/tokens.ts +++ b/pkg/fs/tokens.ts @@ -18,7 +18,8 @@ export const SaveThe = createToken({ pattern: /save the/, }); -/** * The "into the file" statement, used to indicate the file to which to +/** + * The "into the file" statement, used to indicate the file to which to * write. */ export const IntoTheFile = createToken({ diff --git a/pkg/fs/visitor.test.ts b/pkg/fs/visitor.test.ts index 9e767e0b..9c964f2a 100644 --- a/pkg/fs/visitor.test.ts +++ b/pkg/fs/visitor.test.ts @@ -1,6 +1,6 @@ import { visit } from './visitor'; -test('that', async () => { +test('ast is correct', async () => { // Given I have a contract with filesystem statements in it const contract = `Rule unknown ignore Given I have a 'string' named 'stringToWrite' @@ -8,9 +8,18 @@ and I have a 'string' named 'nameOfTheFile' Then I save the 'stringToWrite' into the file 'nameOfTheFile' `; - await visit(contract, { - data: { stringToWrite: 'hello world', nameOfTheFile: 'hello-world.txt' }, - }); - - expect(true).toStrictEqual(true); + // When I generate ast of the contract + const data = { + stringToWrite: 'hello world', + nameOfTheFile: 'hello-world.txt', + }; + const ast = await visit(contract, { data: data }); + // Then the content must be "stringToWrite" + expect(ast.content).toStrictEqual('stringToWrite'); + // and the filename must be "nameOfTheFile" + expect(ast.filename).toStrictEqual('nameOfTheFile'); + // and the value indexed by the content in data must be "hello world" + expect(data[ast.content as 'stringToWrite']).toStrictEqual('hello world'); + // and the value indexed by the filename in data must be "hello-world.txt" + expect(data[ast.filename as 'nameOfTheFile']).toStrictEqual('hello-world.txt'); }); diff --git a/pkg/fs/visitor.ts b/pkg/fs/visitor.ts index a5e5ee7e..b4401cdb 100644 --- a/pkg/fs/visitor.ts +++ b/pkg/fs/visitor.ts @@ -1,7 +1,7 @@ import { BaseFsVisitor, parse, type FileOverrideStatementCtx } from './parser'; -import { type ZenroomParams } from '@slangroom/shared'; -import { type CstNode } from '@slangroom/deps/chevrotain'; +import type { ZenroomParams } from '@slangroom/shared'; +import type { CstNode } from '@slangroom/deps/chevrotain'; export type FileOverrideStatement = { content: string; @@ -23,8 +23,8 @@ class Visitor extends BaseFsVisitor { const content = ctx.content[0].image; const filename = ctx.filename[0].image; return { - content: content, - filename: filename, + content: content.slice(1, -1), + filename: filename.slice(1, -1), }; } } diff --git a/pkg/ignored/index.test.ts b/pkg/ignored/index.test.ts index efc9e996..e4f7d7f2 100644 --- a/pkg/ignored/index.test.ts +++ b/pkg/ignored/index.test.ts @@ -1,6 +1,6 @@ import { getIgnoredStatements } from './index'; -test("that zenroom ignores statements it doesn't know in general", async () => { +test("zenroom ignores statements it doesn't know in general", async () => { // Given I have a contract with a general rule unknown statemets in it const uknowns = [ 'When I test the rule with a statement that does not exist 1', @@ -21,7 +21,7 @@ Then print the data expect(result).toStrictEqual(uknowns); }); -test("that zenroom doesn't ignore ecdh but ignores restroom statements", async () => { +test("zenroom doesn't ignore ecdh but ignores restroom statements", async () => { // Given I have a contract with ecdh and restroom statements const contract = `# Always use 'Rule caller restroom-mw' when using Restroom Rule caller restroom-mw diff --git a/pkg/ignored/index.ts b/pkg/ignored/index.ts index 2f6f4d94..a6d9169c 100644 --- a/pkg/ignored/index.ts +++ b/pkg/ignored/index.ts @@ -1,6 +1,6 @@ import { vocab } from './tokens'; -import { type ZenroomParams, zencodeExec } from '@slangroom/shared'; +import { zencodeExec, type ZenroomParams } from '@slangroom/shared'; import { Lexer } from '@slangroom/deps/chevrotain'; const IgnoredLexer = new Lexer(vocab); diff --git a/pkg/ignored/tokens.ts b/pkg/ignored/tokens.ts index fa3f9386..24f78512 100644 --- a/pkg/ignored/tokens.ts +++ b/pkg/ignored/tokens.ts @@ -4,15 +4,14 @@ import { createToken, CustomPatternMatcherFunc } from '@slangroom/deps/chevrotai /* * Prevent regex-ast annoing warnings * https://github.com/Chevrotain/chevrotain/issues/1670#issuecomment-1001673472 - * */ + */ const wrap = (regex: RegExp): CustomPatternMatcherFunc => { - return (text: string, offset: number): RegExpExecArray | null => { - const re = new RegExp(regex, 'y'); - re.lastIndex = offset - return re.exec(text) - } -} - + return (text: string, offset: number): RegExpExecArray | null => { + const re = new RegExp(regex, 'y'); + re.lastIndex = offset; + return re.exec(text); + }; +}; /** * Statements ignored by Zenroom. diff --git a/pkg/shared/tokens.test.ts b/pkg/shared/tokens.test.ts index 17d50f74..2e4f9142 100644 --- a/pkg/shared/tokens.test.ts +++ b/pkg/shared/tokens.test.ts @@ -24,7 +24,7 @@ test('that identifiers are identified correctly', () => { 'four' # blanks here and there 'five' # mix of blanks and tabs `; - // When I lex the it + // When I lex it const lexed = lex(contract); // Then I must have no errors expect(lexed.errors).toHaveLength(0); @@ -58,7 +58,7 @@ test('that identifiers are identified correctly', () => { /* eslint-enable */ }); -test('that non-matcheds error out', () => { +test('non-matcheds error out', () => { // Given I have a broken contract const contract = `broken contract`; // When I lex it @@ -82,7 +82,7 @@ test('that non-matcheds error out', () => { ]); }); -test('that tokens are skipped correctly', () => { +test('tokens are skipped correctly', () => { // Given I have a contract with several ignored and an identifier tokens const contract = "given I am 'alice'"; // When I lex it diff --git a/pkg/shared/zenroom.test.ts b/pkg/shared/zenroom.test.ts index e2474913..f5a11cca 100644 --- a/pkg/shared/zenroom.test.ts +++ b/pkg/shared/zenroom.test.ts @@ -1,6 +1,6 @@ -import { convZenParams } from './zenroom'; +import { convZenParams, zencodeExec, ZenroomError } from './zenroom'; -test('that convZenParams() works', () => { +test('convZenParams() works', () => { // Since TS already covers our butts regarding type checks, we just // need to convice the coverage here that all the code paths are // taken. @@ -44,3 +44,25 @@ test('that convZenParams() works', () => { expect(result).toStrictEqual({ data: JSON.stringify(data), keys: JSON.stringify(keys) }); } }); + +describe('zencode()', () => { + test("doesn't throw with valid input", async () => { + // Given I have a valid contract + const contract = `Given I have nothing +Then I print string 'I love you' +`; + // When I execute the contract + const promise = zencodeExec(contract); + // Then it must not throw any errors + await expect(promise).resolves.toBeTruthy(); + }); + + test('throws with invalid input', async () => { + // Given I have an invalid contract + const contract = "I'm invalid."; + // When I execute the contract + const promise = zencodeExec(contract); + // Then it must throw some errors + await expect(promise).rejects.toThrow(ZenroomError); + }); +}); diff --git a/pkg/shared/zenroom.ts b/pkg/shared/zenroom.ts index a6d04ef8..18e70283 100644 --- a/pkg/shared/zenroom.ts +++ b/pkg/shared/zenroom.ts @@ -10,6 +10,16 @@ export type ZenroomResult = { logs: string; }; +/** + * Error thrown by [zenroomExec] if contract execution somehow fails. + */ +export class ZenroomError extends Error { + constructor(logs: string) { + super(logs); + this.name = 'ZenroomError'; + } +} + /** * Zenroom parameters suitable for zencode_exec() (after each value's * been piped to JSON.stringify()). @@ -51,8 +61,15 @@ export const convZenParams = (params?: ZenroomParams): ZenroomStringParams => { * @param contract is a zencode contract. * @param params is parameters to Zenroom. * @returns the output of Zenroom. + * @throws {ZenroomError} if execution of a contract fails. */ export const zencodeExec = async ( contract: string, params?: ZenroomParams -): Promise => await zencode_exec(contract, convZenParams(params)); +): Promise => { + try { + return await zencode_exec(contract, convZenParams(params)); + } catch (e) { + throw new ZenroomError(e.logs); + } +}; diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index ed584239..30db7524 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,2 +1,2 @@ packages: - - 'pkg/*' + - pkg/*