Skip to content

Commit

Permalink
feat(core): synonymize "open" and "connect to"
Browse files Browse the repository at this point in the history
Now, "open" and "connect to" are synonyms.  Added two new method signature to
PluginContext as well, getOpen() and fetchOpen(), which are synonyms to
getOpen() and fetchOpen() too.
  • Loading branch information
denizenging committed Oct 13, 2023
1 parent bdefa5e commit b822da6
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 48 deletions.
20 changes: 14 additions & 6 deletions pkg/core/src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
And,
Buzzword,
Connect,
Open,
Identifier,
Into,
Output,
Expand All @@ -14,14 +15,14 @@ import { CstParser, type IToken, type CstNode } from '@slangroom/deps/chevrotain

export type StatementCst = CstNode & {
children: {
connect?: ConnectCst;
openconnect?: OpenconnectCst;
sendpass: SendpassCst[];
phrase: PhraseCst;
into?: IntoCst;
};
};

export type ConnectCst = CstNode & {
export type OpenconnectCst = CstNode & {
children: { Identifier: [IToken] };
};

Expand Down Expand Up @@ -49,15 +50,22 @@ const Parser = new (class extends CstParser {
}

statement = this.RULE('statement', () => {
this.OPTION1(() => this.SUBRULE(this.#connect));
this.OPTION1(() => this.SUBRULE(this.#openconnect));
this.MANY(() => this.SUBRULE(this.#sendpass));
this.SUBRULE(this.#phrase);
this.OPTION2(() => this.SUBRULE(this.#into));
});

#connect = this.RULE('connect', () => {
this.CONSUME(Connect);
this.CONSUME(To);
#openconnect = this.RULE('openconnect', () => {
this.OR([
{ ALT: () => this.CONSUME(Open) },
{
ALT: () => {
this.CONSUME(Connect);
this.CONSUME(To);
},
},
]);
this.CONSUME(Identifier);
this.CONSUME(And);
});
Expand Down
72 changes: 56 additions & 16 deletions pkg/core/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,33 @@ export type PluginContext = {
phrase: string;

/**
* Gets the value of the Connect part of a Statement« if available.
* Gets the value of the Open or Connect part of a Statement, if available.
*
* @returns The array of values of the Connect part (might be empty).
* @returns The array of values of the Open or Connect part (might be
* empty).
*/
getConnect(): string[];

/**
* Basically the same as {@link getConnect}, but throws if unavailable or empty.
*
* @returns The array of values of the Connect part (has at least one item);
* @returns The array of values of the Open or Connect part (has at least
* one item).
*
* @throws {@link Error} if the part is unavailable.
*/
fetchConnect(): [string, ...string[]];

/**
* {@inheritDoc getConnect}
*/
getOpen(): string[];

/**
* {@inheritDoc fetchConnect}
*/
fetchOpen(): [string, ...string[]];

/**
* Gets the value of the parameter needed by the Plugin, if available.
*
Expand Down Expand Up @@ -106,10 +118,10 @@ export class PluginContextImpl implements PluginContext {
readonly phrase: string;

/**
* The name of the identifier used to reference the Connection parameters
* (via {@link #zparams}). It is an rhs value.
* The name of the identifier used to reference the Open or Connect
* parameters (via {@link #zparams}). It is an rhs value.
*/
#connect: string | undefined = undefined;
#openconnect: string | undefined = undefined;

/**
* A map between parameters that should be provided to a statetment and
Expand All @@ -129,7 +141,7 @@ export class PluginContextImpl implements PluginContext {

constructor(stmt: Statement, zparams: ZenParams) {
this.phrase = stmt.phrase.toLowerCase();
this.#connect = stmt.connect;
this.#openconnect = stmt.openconnect;
this.#bindings = stmt.bindings;
this.#zparams = zparams;
}
Expand Down Expand Up @@ -159,14 +171,14 @@ export class PluginContextImpl implements PluginContext {
* {@inheritDoc PluginContext.getConnect}
*/
getConnect(): string[] {
if (!this.#connect) return [];
const val = this.#getDataKeys(this.#connect);
if (!this.#openconnect) return [];
const val = this.#getDataKeys(this.#openconnect);
if (typeof val === 'string') return [val];
if (Array.isArray(val)) {
if (val.every((x) => typeof x === 'string')) return val as string[];
else
throw new Error(
`the array referenced by ${this.#connect} must solely composed of strings`
`the array referenced by ${this.#openconnect} must solely composed of strings`

Check warning on line 181 in pkg/core/src/plugin.ts

View check run for this annotation

Codecov / codecov/patch

pkg/core/src/plugin.ts#L181

Added line #L181 was not covered by tests
);
}
return [];
Expand All @@ -181,6 +193,20 @@ export class PluginContextImpl implements PluginContext {
return val as [string, ...string[]];
}

/**
* {@inheritDoc PluginContext.getOpen}
*/
getOpen(): string[] {
return this.getConnect();
}

Check warning on line 201 in pkg/core/src/plugin.ts

View check run for this annotation

Codecov / codecov/patch

pkg/core/src/plugin.ts#L200-L201

Added lines #L200 - L201 were not covered by tests

/**
* {@inheritDoc PluginContext.fetchOpen}
*/
fetchOpen(): [string, ...string[]] {
return this.fetchConnect();
}

/**
* {@inheritDoc PluginContext.get}
*/
Expand Down Expand Up @@ -210,20 +236,20 @@ export class PluginContextImpl implements PluginContext {
* @internal
*/
export class PluginContextTest implements PluginContext {
#connect: string[] = [];
#openconnect: string[] = [];
#params = new Map<string, Jsonable>();
readonly phrase: string = ''; // not used but required by the interface

constructor(connect: string | string[], params: Record<string, Jsonable>) {
this.#connect = typeof connect === 'string' ? [connect] : connect;
constructor(openconnect: string | string[], params: Record<string, Jsonable>) {
this.#openconnect = typeof openconnect === 'string' ? [openconnect] : openconnect;
this.#params = new Map(Object.entries(params));
}

/**
* @constructor
*/
static connect(connect: string | string[]) {
return new this(connect, {});
static openconnect(openconnect: string | string[]) {
return new this(openconnect, {});
}

/**
Expand Down Expand Up @@ -251,7 +277,7 @@ export class PluginContextTest implements PluginContext {
* {@inheritDoc PluginContext.getConnect}
*/
getConnect(): string[] {
return this.#connect;
return this.#openconnect;
}

/**
Expand All @@ -263,6 +289,20 @@ export class PluginContextTest implements PluginContext {
return val as [string, ...string[]];
}

/**
* {@inheritDoc PluginContext.getOpen}
*/
getOpen(): string[] {
return this.getConnect();
}

Check warning on line 297 in pkg/core/src/plugin.ts

View check run for this annotation

Codecov / codecov/patch

pkg/core/src/plugin.ts#L296-L297

Added lines #L296 - L297 were not covered by tests

/**
* {@inheritDoc PluginContext.fetchOpen}
*/
fetchOpen(): [string, ...string[]] {
return this.fetchConnect();
}

Check warning on line 304 in pkg/core/src/plugin.ts

View check run for this annotation

Codecov / codecov/patch

pkg/core/src/plugin.ts#L303-L304

Added lines #L303 - L304 were not covered by tests

/**
* {@inheritDoc PluginContext.get}
*/
Expand Down
6 changes: 6 additions & 0 deletions pkg/core/src/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ export const Connect = createToken({
pattern: /connect/i,
});

export const Open = createToken({
name: 'Open',
pattern: /open/i,
});

export const To = createToken({
name: 'To',
pattern: /to/i,
Expand Down Expand Up @@ -51,6 +56,7 @@ export const And = createToken({
export const allTokens = [
Whitespace,
Connect,
Open,
Into,
Output,
And,
Expand Down
10 changes: 5 additions & 5 deletions pkg/core/src/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import {
type PhraseCst,
type IntoCst,
type SendpassCst,
type ConnectCst,
type OpenconnectCst,
} from '@slangroom/core';
import type { IToken } from '@slangroom/deps/chevrotain';

export type Statement = {
connect?: string;
openconnect?: string;
bindings: Map<string, string>;
phrase: string;
into?: string;
Expand All @@ -27,7 +27,7 @@ interface V {
visit(cst: StatementCst): ReturnType<this['statement']>;
visit(cst: PhraseCst): ReturnType<this['phrase']>;
visit(cst: SendpassCst): ReturnType<this['sendpass']>;
visit(cst: ConnectCst): ReturnType<this['connect']>;
visit(cst: OpenconnectCst): ReturnType<this['openconnect']>;
visit(cst: IntoCst): ReturnType<this['into']>;
}

Expand All @@ -47,7 +47,7 @@ class V extends CstVisitor {
if (stmt.bindings.has(key)) throw new ErrorKeyExists(key);
stmt.bindings.set(key, value);
});
if (ctx.connect) stmt.connect = this.visit(ctx.connect);
if (ctx.openconnect) stmt.openconnect = this.visit(ctx.openconnect);
if (ctx.into) stmt.into = this.visit(ctx.into);
return stmt;
}
Expand All @@ -60,7 +60,7 @@ class V extends CstVisitor {
return [this.visit(ctx.phrase), ctx.Identifier[0].image.slice(1, -1)];
}

connect(ctx: ConnectCst['children']): string {
openconnect(ctx: OpenconnectCst['children']): string {
return ctx.Identifier[0].image.slice(1, -1);
}

Expand Down
27 changes: 26 additions & 1 deletion pkg/core/test/slangroom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ test('runs all unknown statements', async (t) => {
let usedP0 = false;
let usedP1 = false;
let usedP2 = false;
let usedP3 = false;
let usedP4 = false;

const p0 = (ctx: PluginContext): PluginResult => {
if (ctx.phrase === 'a') {
Expand Down Expand Up @@ -32,6 +34,25 @@ test('runs all unknown statements', async (t) => {
return ctx.fail('Unkown phrase');
};

const p3 = (ctx: PluginContext): PluginResult => {
if (ctx.phrase === 'e f') {
usedP3 = true;
t.is(ctx.fetchOpen()[0], 'bar');
return ctx.pass(null);
}
return ctx.fail('Unkown phrase');
};

const p4 = (ctx: PluginContext): PluginResult => {
if (ctx.phrase === 'f g') {
usedP4 = true;
t.is(ctx.fetchConnect()[0], 'foo');
return ctx.pass(null);
}
return ctx.fail('Unkown phrase');
};


const script = `
Rule caller restroom-mw
Given I A and output into 'a'
Expand All @@ -42,11 +63,15 @@ Then print 'a'
Then I pass a 'a' and B and output into 'b'
Then I pass a 'b' and c D
Then I pass a 'b' and C d and output into 'mimmo'
Then I open 'b' and e F
Then I connect to 'a' and F g
`;
const slangroom = new Slangroom(p0, [p1, new Set([p2])]);
const slangroom = new Slangroom(p0, [p1, new Set([p2]), p3], p4);
const res = await slangroom.execute(script);
t.true(usedP0);
t.true(usedP1);
t.true(usedP2);
t.true(usedP3);
t.true(usedP4);
t.deepEqual(res.result, { a: 'foo', b: 'bar', mimmo: 'foobar' }, res.logs);
});
38 changes: 19 additions & 19 deletions pkg/core/test/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,29 @@ test('generated ast is correct', async (t) => {
]),
},
"connect to 'foo' and read the ethereum balance": {
connect: 'foo',
openconnect: 'foo',
phrase: 'read the ethereum balance',
bindings: new Map<string, string>(),
},
"connect to 'foo' and pass address 'addr' and send contract 'contract' and read the ethereum balance":
{
connect: 'foo',
phrase: 'read the ethereum balance',
bindings: new Map<string, string>([
['address', 'addr'],
['contract', 'contract'],
]),
},
"connect to 'foo' and pass address 'addr' and send contract 'contract' and read the ethereum balance and output into 'var'":
{
connect: 'foo',
phrase: 'read the ethereum balance',
bindings: new Map<string, string>([
['address', 'addr'],
['contract', 'contract'],
]),
into: 'var',
},
{
openconnect: 'foo',
phrase: 'read the ethereum balance',
bindings: new Map<string, string>([
['address', 'addr'],
['contract', 'contract'],
]),
},
"open 'foo' and pass address 'addr' and send contract 'contract' and read the ethereum balance and output into 'var'":
{
openconnect: 'foo',
phrase: 'read the ethereum balance',
bindings: new Map<string, string>([
['address', 'addr'],
['contract', 'contract'],
]),
into: 'var',
},
};

for (const [line, astWant] of Object.entries(cases)) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/http/test/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ test('Simple GET', async (t) => {
return;
}

const ctx = PluginContextTest.connect('http://localhost/normaljson');
const ctx = PluginContextTest.openconnect('http://localhost/normaljson');
const res = await execute(ctx, ast.kind, ast.method);
t.deepEqual(res, {
ok: true,
Expand Down

0 comments on commit b822da6

Please sign in to comment.