Skip to content

Commit 6b3083e

Browse files
committed
Implement O() and RV().
1 parent c535c4e commit 6b3083e

File tree

2 files changed

+225
-10
lines changed

2 files changed

+225
-10
lines changed

src/parser.spec.ts

+183-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ describe('parser tests', (): void => {
7070
]);
7171
});
7272
it('semantic markup test', (): void => {
73-
expect(parse('foo E(a\\),b) P(foo.bar.baz , bam) baz V( b\\,\\na\\)\\\\m\\, ) ')).toEqual([
73+
expect(parse('foo E(a\\),b) P(foo.bar.baz , bam) baz V( b\\,\\na\\)\\\\m\\, ) O(foo) ')).toEqual([
7474
[
7575
{ type: PartType.TEXT, text: 'foo ' },
7676
{ type: PartType.ENV_VARIABLE, name: 'a),b' },
@@ -79,6 +79,188 @@ describe('parser tests', (): void => {
7979
{ type: PartType.TEXT, text: ' baz ' },
8080
{ type: PartType.OPTION_VALUE, value: ' b,na)\\m, ' },
8181
{ type: PartType.TEXT, text: ' ' },
82+
{ type: PartType.OPTION_NAME, plugin: undefined, link: ['foo'], name: 'foo', value: undefined },
83+
{ type: PartType.TEXT, text: ' ' },
84+
],
85+
]);
86+
});
87+
it('semantic markup option name', (): void => {
88+
expect(parse('O(foo)')).toEqual([
89+
[
90+
{
91+
type: PartType.OPTION_NAME,
92+
plugin: undefined,
93+
link: ['foo'],
94+
name: 'foo',
95+
value: undefined,
96+
},
97+
],
98+
]);
99+
expect(parse('O(ignore:foo)', { current_plugin: { fqcn: 'foo.bar.baz', type: 'bam' } })).toEqual([
100+
[
101+
{
102+
type: PartType.OPTION_NAME,
103+
plugin: undefined,
104+
link: ['foo'],
105+
name: 'foo',
106+
value: undefined,
107+
},
108+
],
109+
]);
110+
expect(parse('O(foo)', { current_plugin: { fqcn: 'foo.bar.baz', type: 'bam' } })).toEqual([
111+
[
112+
{
113+
type: PartType.OPTION_NAME,
114+
plugin: { fqcn: 'foo.bar.baz', type: 'bam' },
115+
link: ['foo'],
116+
name: 'foo',
117+
value: undefined,
118+
},
119+
],
120+
]);
121+
expect(parse('O(foo.bar.baz#bam:foo)')).toEqual([
122+
[
123+
{
124+
type: PartType.OPTION_NAME,
125+
plugin: { fqcn: 'foo.bar.baz', type: 'bam' },
126+
link: ['foo'],
127+
name: 'foo',
128+
value: undefined,
129+
},
130+
],
131+
]);
132+
expect(parse('O(foo=bar)')).toEqual([
133+
[
134+
{
135+
type: PartType.OPTION_NAME,
136+
plugin: undefined,
137+
link: ['foo'],
138+
name: 'foo',
139+
value: 'bar',
140+
},
141+
],
142+
]);
143+
expect(parse('O(foo.baz=bam)')).toEqual([
144+
[
145+
{
146+
type: PartType.OPTION_NAME,
147+
plugin: undefined,
148+
link: ['foo', 'baz'],
149+
name: 'foo.baz',
150+
value: 'bam',
151+
},
152+
],
153+
]);
154+
expect(parse('O(foo[1].baz[bam.bar.boing].boo)')).toEqual([
155+
[
156+
{
157+
type: PartType.OPTION_NAME,
158+
plugin: undefined,
159+
link: ['foo', 'baz', 'boo'],
160+
name: 'foo[1].baz[bam.bar.boing].boo',
161+
value: undefined,
162+
},
163+
],
164+
]);
165+
expect(parse('O(bar.baz.bam.boo#lookup:foo[1].baz[bam.bar.boing].boo)')).toEqual([
166+
[
167+
{
168+
type: PartType.OPTION_NAME,
169+
plugin: { fqcn: 'bar.baz.bam.boo', type: 'lookup' },
170+
link: ['foo', 'baz', 'boo'],
171+
name: 'foo[1].baz[bam.bar.boing].boo',
172+
value: undefined,
173+
},
174+
],
175+
]);
176+
});
177+
it('semantic markup return value name', (): void => {
178+
expect(parse('RV(foo)')).toEqual([
179+
[
180+
{
181+
type: PartType.RETURN_VALUE,
182+
plugin: undefined,
183+
link: ['foo'],
184+
name: 'foo',
185+
value: undefined,
186+
},
187+
],
188+
]);
189+
expect(parse('RV(ignore:foo)', { current_plugin: { fqcn: 'foo.bar.baz', type: 'bam' } })).toEqual([
190+
[
191+
{
192+
type: PartType.RETURN_VALUE,
193+
plugin: undefined,
194+
link: ['foo'],
195+
name: 'foo',
196+
value: undefined,
197+
},
198+
],
199+
]);
200+
expect(parse('RV(foo)', { current_plugin: { fqcn: 'foo.bar.baz', type: 'bam' } })).toEqual([
201+
[
202+
{
203+
type: PartType.RETURN_VALUE,
204+
plugin: { fqcn: 'foo.bar.baz', type: 'bam' },
205+
link: ['foo'],
206+
name: 'foo',
207+
value: undefined,
208+
},
209+
],
210+
]);
211+
expect(parse('RV(foo.bar.baz#bam:foo)')).toEqual([
212+
[
213+
{
214+
type: PartType.RETURN_VALUE,
215+
plugin: { fqcn: 'foo.bar.baz', type: 'bam' },
216+
link: ['foo'],
217+
name: 'foo',
218+
value: undefined,
219+
},
220+
],
221+
]);
222+
expect(parse('RV(foo=bar)')).toEqual([
223+
[
224+
{
225+
type: PartType.RETURN_VALUE,
226+
plugin: undefined,
227+
link: ['foo'],
228+
name: 'foo',
229+
value: 'bar',
230+
},
231+
],
232+
]);
233+
expect(parse('RV(foo.baz=bam)')).toEqual([
234+
[
235+
{
236+
type: PartType.RETURN_VALUE,
237+
plugin: undefined,
238+
link: ['foo', 'baz'],
239+
name: 'foo.baz',
240+
value: 'bam',
241+
},
242+
],
243+
]);
244+
expect(parse('RV(foo[1].baz[bam.bar.boing].boo)')).toEqual([
245+
[
246+
{
247+
type: PartType.RETURN_VALUE,
248+
plugin: undefined,
249+
link: ['foo', 'baz', 'boo'],
250+
name: 'foo[1].baz[bam.bar.boing].boo',
251+
value: undefined,
252+
},
253+
],
254+
]);
255+
expect(parse('RV(bar.baz.bam.boo#lookup:foo[1].baz[bam.bar.boing].boo)')).toEqual([
256+
[
257+
{
258+
type: PartType.RETURN_VALUE,
259+
plugin: { fqcn: 'bar.baz.bam.boo', type: 'lookup' },
260+
link: ['foo', 'baz', 'boo'],
261+
name: 'foo[1].baz[bam.bar.boing].boo',
262+
value: undefined,
263+
},
82264
],
83265
]);
84266
});

src/parser.ts

+42-9
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,9 @@ export interface CodePart extends Part {
7878

7979
export interface OptionNamePart extends Part {
8080
type: PartType.OPTION_NAME;
81-
ignore: boolean;
8281
plugin: PluginIdentifier | undefined;
83-
option_link: string;
84-
option: string;
82+
link: string[];
83+
name: string;
8584
value: string | undefined;
8685
}
8786

@@ -97,10 +96,9 @@ export interface EnvVariablePart extends Part {
9796

9897
export interface ReturnValuePart extends Part {
9998
type: PartType.RETURN_VALUE;
100-
ignore: boolean;
10199
plugin: PluginIdentifier | undefined;
102-
return_value_link: string;
103-
return_value: string;
100+
link: string[];
101+
name: string;
104102
value: string | undefined;
105103
}
106104

@@ -132,13 +130,48 @@ export type AnyPart =
132130

133131
export type Paragraph = AnyPart[];
134132

133+
const IGNORE_MARKER = 'ignore:';
134+
135135
function parseOptionLike(
136-
value: string,
136+
text: string,
137137
opts: ParsingOptions,
138138
type: PartType.OPTION_NAME | PartType.RETURN_VALUE,
139139
): OptionNamePart | ReturnValuePart {
140-
// TODO
141-
throw Error('Not yet supported');
140+
let value: string | undefined;
141+
const eq = text.indexOf('=');
142+
if (eq >= 0) {
143+
value = text.substring(eq + 1, text.length);
144+
text = text.substring(0, eq);
145+
}
146+
const m = /^([^.]+\.[^.]+\.[^#]+)#([a-z]+):(.*)$/.exec(text);
147+
let plugin: PluginIdentifier | undefined;
148+
if (m) {
149+
const pluginFqcn = m[1] as string;
150+
const pluginType = m[2] as string;
151+
if (!isFQCN(pluginFqcn)) {
152+
throw Error(`Plugin name "${pluginFqcn}" is not a FQCN`);
153+
}
154+
if (!isPluginType(pluginType)) {
155+
throw Error(`Plugin type "${pluginType}" is not valid`);
156+
}
157+
plugin = { fqcn: pluginFqcn, type: pluginType };
158+
text = m[3] as string;
159+
} else if (text.startsWith(IGNORE_MARKER)) {
160+
plugin = undefined;
161+
text = text.substring(IGNORE_MARKER.length, text.length);
162+
} else {
163+
plugin = opts.current_plugin;
164+
}
165+
if (/[:#]/.test(text)) {
166+
throw Error(`Invalid option/return value name "${text}"`);
167+
}
168+
return {
169+
type: type,
170+
plugin: plugin,
171+
link: text.replace(/\[([^\]]*)\]/g, '').split('.'),
172+
name: text,
173+
value: value,
174+
};
142175
}
143176

144177
interface CommandParser {

0 commit comments

Comments
 (0)