spex-parser 0.6.2 → 0.7.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.
@@ -96,6 +96,19 @@ describe('SpexParser', () => {
96
96
  expect(parser.errors).toHaveLength(0)
97
97
  })
98
98
 
99
+ it('should parse subobject declaration with a structured constraint', () => {
100
+ const testCase = 'create double as from number -> number select ```\nreturn n * 2\n```;'
101
+ const { parser } = parseInput(testCase)
102
+ expect(parser.errors).toHaveLength(0)
103
+ })
104
+
105
+ it('should parse subobject declaration with a code constraint', () => {
106
+ const testCase =
107
+ 'create double as from number -> number select ```python\nreturn @n * 2\n```;'
108
+ const { parser } = parseInput(testCase)
109
+ expect(parser.errors).toHaveLength(0)
110
+ })
111
+
99
112
  it('should parse subobject declaration with a set operation base', () => {
100
113
  const testCase =
101
114
  'create MySubobject as from Web intersect TypeScript select { is an express app };'
@@ -164,6 +177,12 @@ describe('SpexParser', () => {
164
177
  expect(parser.errors).toHaveLength(0)
165
178
  })
166
179
 
180
+ it('should parse basic object artifact', () => {
181
+ const testCase = 'create MyObject as artifact;'
182
+ const { parser } = parseInput(testCase)
183
+ expect(parser.errors).toHaveLength(0)
184
+ })
185
+
167
186
  it('should parse basic objects in product fields', () => {
168
187
  const testCase = 'create Config as (name: string, count: number, active: bool);'
169
188
  const { parser } = parseInput(testCase)
@@ -205,6 +224,12 @@ describe('SpexParser', () => {
205
224
  const { parser } = parseInput(testCase)
206
225
  expect(parser.errors).not.toHaveLength(0)
207
226
  })
227
+
228
+ it('should not allow overriding basic object artifact', () => {
229
+ const testCase = 'create artifact as Number;'
230
+ const { parser } = parseInput(testCase)
231
+ expect(parser.errors).not.toHaveLength(0)
232
+ })
208
233
  })
209
234
 
210
235
  describe('import declaration', () => {
@@ -227,88 +252,30 @@ describe('SpexParser', () => {
227
252
  })
228
253
  })
229
254
 
230
- describe('export declaration', () => {
231
- it('should parse export declaration', () => {
232
- const testCase = 'export EmailAddress;'
233
- const { parser } = parseInput(testCase)
234
- expect(parser.errors).toHaveLength(0)
235
- })
236
- })
237
-
238
255
  describe('generate declaration', () => {
239
256
  it('should parse generate declaration', () => {
240
257
  const testCase = 'generate Main;'
241
258
  const { parser } = parseInput(testCase)
242
259
  expect(parser.errors).toHaveLength(0)
243
260
  })
244
- })
245
261
 
246
- describe('enum object', () => {
247
- it('should parse enum object declaration', () => {
248
- const testCase = "create myEnum as enum ('v1', 'v2');"
262
+ it('should parse generate declaration with an environment', () => {
263
+ const testCase = 'generate Main in Python;'
249
264
  const { parser } = parseInput(testCase)
250
265
  expect(parser.errors).toHaveLength(0)
251
266
  })
252
267
 
253
- it('should parse enum object declaration case-insensitively', () => {
254
- const testCase = "CREATE myEnum AS ENUM ('v1', 'v2');"
268
+ it('should parse generate declaration with a dotted environment', () => {
269
+ const testCase = 'generate Main in dev.Linux;'
255
270
  const { parser } = parseInput(testCase)
256
271
  expect(parser.errors).toHaveLength(0)
257
272
  })
258
273
 
259
- it('should parse single-value enum object', () => {
260
- const testCase = "create Status as enum ('ACTIVE');"
274
+ it('should parse generate declaration with an environment subobject', () => {
275
+ const testCase = 'generate Main in from environment select { python };'
261
276
  const { parser } = parseInput(testCase)
262
277
  expect(parser.errors).toHaveLength(0)
263
278
  })
264
-
265
- it('should parse enum object with double quoted values', () => {
266
- const testCase = 'create myEnum as enum ("v1", "v2");'
267
- const { parser } = parseInput(testCase)
268
- expect(parser.errors).toHaveLength(0)
269
- })
270
-
271
- it('should parse enum object with mixed quote values', () => {
272
- const testCase = "create myEnum as enum (\"v1\", 'v2');"
273
- const { parser } = parseInput(testCase)
274
- expect(parser.errors).toHaveLength(0)
275
- })
276
-
277
- it('should parse enum object with escaped values', () => {
278
- const testCase = "create myEnum as enum ('it\\'s');"
279
- const { parser } = parseInput(testCase)
280
- expect(parser.errors).toHaveLength(0)
281
- })
282
-
283
- it('should parse enum object inside a product object', () => {
284
- const testCase = "create Config as (kind: enum ('a', 'b'));"
285
- const { parser } = parseInput(testCase)
286
- expect(parser.errors).toHaveLength(0)
287
- })
288
-
289
- it('should parse array of enum object', () => {
290
- const testCase = "create myEnum as enum ('a', 'b')[];"
291
- const { parser } = parseInput(testCase)
292
- expect(parser.errors).toHaveLength(0)
293
- })
294
-
295
- it('should not parse enum object without values', () => {
296
- const testCase = 'create myEnum as enum ();'
297
- const { parser } = parseInput(testCase)
298
- expect(parser.errors).not.toHaveLength(0)
299
- })
300
-
301
- it('should not parse enum object with a trailing comma', () => {
302
- const testCase = "create myEnum as enum ('v1',);"
303
- const { parser } = parseInput(testCase)
304
- expect(parser.errors).not.toHaveLength(0)
305
- })
306
-
307
- it('should not parse enum object without parentheses', () => {
308
- const testCase = 'create myEnum as enum;'
309
- const { parser } = parseInput(testCase)
310
- expect(parser.errors).not.toHaveLength(0)
311
- })
312
279
  })
313
280
 
314
281
  describe('literal object', () => {
@@ -515,76 +482,6 @@ describe('SpexParser', () => {
515
482
  })
516
483
  })
517
484
 
518
- describe('package declaration', () => {
519
- it('should parse package executable declaration', () => {
520
- const testCase = 'package executable myapp as Main in Python;'
521
- const { parser } = parseInput(testCase)
522
- expect(parser.errors).toHaveLength(0)
523
- })
524
-
525
- it('should parse package module declaration', () => {
526
- const testCase = 'package module mylib as utils in Node;'
527
- const { parser } = parseInput(testCase)
528
- expect(parser.errors).toHaveLength(0)
529
- })
530
-
531
- it('should parse package executable with exponential object', () => {
532
- const testCase = 'package executable cli as (path: string) -> unit in Python;'
533
- const { parser } = parseInput(testCase)
534
- expect(parser.errors).toHaveLength(0)
535
- })
536
-
537
- it('should parse package executable with dotted name', () => {
538
- const testCase = 'package executable myapp as app.Main in Python;'
539
- const { parser } = parseInput(testCase)
540
- expect(parser.errors).toHaveLength(0)
541
- })
542
-
543
- it('should parse package module with array type', () => {
544
- const testCase = 'package module mylib as string[] in Python;'
545
- const { parser } = parseInput(testCase)
546
- expect(parser.errors).toHaveLength(0)
547
- })
548
-
549
- it('should parse package executable with product type', () => {
550
- const testCase = 'package module mylib as (name: string, count: number) in Python;'
551
- const { parser } = parseInput(testCase)
552
- expect(parser.errors).toHaveLength(0)
553
- })
554
-
555
- it('should parse package executable with subobject', () => {
556
- const testCase =
557
- 'package executable myapp as from string select { is a valid command } in Python;'
558
- const { parser } = parseInput(testCase)
559
- expect(parser.errors).toHaveLength(0)
560
- })
561
-
562
- it('should parse package declaration case-insensitively', () => {
563
- const testCase = 'PACKAGE EXECUTABLE myapp AS Main IN Python;'
564
- const { parser } = parseInput(testCase)
565
- expect(parser.errors).toHaveLength(0)
566
- })
567
-
568
- it('should parse mixed package and generate declarations', () => {
569
- const testCase = 'package executable myapp as Main in Python;\ngenerate Main;'
570
- const { parser } = parseInput(testCase)
571
- expect(parser.errors).toHaveLength(0)
572
- })
573
-
574
- it('should parse package declaration with complex nested type', () => {
575
- const testCase =
576
- 'package module mylib as from (x: number, y: number) -> number select { computes distance } in Node;'
577
- const { parser } = parseInput(testCase)
578
- expect(parser.errors).toHaveLength(0)
579
- })
580
-
581
- it('should parse package with complex environment object', () => {
582
- const testCase = 'package executable myapp as Main in from environment select { python };'
583
- const { parser } = parseInput(testCase)
584
- expect(parser.errors).toHaveLength(0)
585
- })
586
- })
587
-
588
485
  describe('comments', () => {
589
486
  it('should parse declarations separated by single-line comments', () => {
590
487
  const testCase = `
@@ -641,7 +538,6 @@ describe('SpexParser', () => {
641
538
  const testCase = `
642
539
  create Todo as (id: string, title: string, completed: bool);
643
540
  create EmailAddress as from string select { are email addresses };
644
- export EmailAddress;
645
541
  generate Main;
646
542
  `
647
543
  const { parser } = parseInput(testCase)
@@ -737,50 +633,4 @@ describe('SpexParser', () => {
737
633
  expect(parser.errors).not.toHaveLength(0)
738
634
  })
739
635
  })
740
-
741
- describe('lambda object', () => {
742
- it('should parse lambda with product base', () => {
743
- const testCase = 'create sum as lambda (a: number, b: number) -> number ```python\nreturn a + b\n```;'
744
- const { parser } = parseInput(testCase)
745
- expect(parser.errors).toHaveLength(0)
746
- })
747
-
748
- it('should parse lambda with named base', () => {
749
- const testCase = 'create double as lambda number -> number ```python\nreturn @n * 2\n```;'
750
- const { parser } = parseInput(testCase)
751
- expect(parser.errors).toHaveLength(0)
752
- })
753
-
754
- it('should parse lambda case-insensitively', () => {
755
- const testCase = 'create sum as LAMBDA (a: number) -> number ```python\nreturn @a\n```;'
756
- const { parser } = parseInput(testCase)
757
- expect(parser.errors).toHaveLength(0)
758
- })
759
-
760
- it('should parse lambda with pattern blocks', () => {
761
- const testCase =
762
- 'create transform as lambda (x: number) -> number ```python\nif @x > 0:\n @{return sin(@x)}\nelse:\n @{return cos(@x)}\n```;'
763
- const { parser } = parseInput(testCase)
764
- expect(parser.errors).toHaveLength(0)
765
- })
766
-
767
- it('should parse lambda in product field', () => {
768
- const testCase =
769
- 'create Config as (handler: lambda (x: string) -> string ```typescript\nreturn x.toUpperCase();\n```, port: number);'
770
- const { parser } = parseInput(testCase)
771
- expect(parser.errors).toHaveLength(0)
772
- })
773
-
774
- it('should not parse lambda without language', () => {
775
- const testCase = 'create sum as lambda (a: number) -> number ```\nreturn @a\n```;'
776
- const { parser } = parseInput(testCase)
777
- expect(parser.errors).not.toHaveLength(0)
778
- })
779
-
780
- it('should not parse lambda without code block', () => {
781
- const testCase = 'create sum as lambda (a: number) -> number;'
782
- const { parser } = parseInput(testCase)
783
- expect(parser.errors).not.toHaveLength(0)
784
- })
785
- })
786
636
  })
@@ -104,5 +104,4 @@ realize TodoWeb as (
104
104
  main: ExpressTodoWeb
105
105
  ) in ExpressWebEnv;
106
106
 
107
- generate ExpressTodoWeb;
108
- package executable expresstodo as ExpressTodoWeb in ExpressWebEnv;
107
+ generate TodoWeb in ExpressWebEnv;
@@ -12,5 +12,3 @@ select {
12
12
  dependencies: express,
13
13
  database: PostgreSQL
14
14
  };
15
-
16
- export ExpressWebEnv;
@@ -107,5 +107,4 @@ realize TodoWeb as (
107
107
  main: FlaskTodoWeb
108
108
  ) in FlaskWebEnv;
109
109
 
110
- generate FlaskTodoWeb;
111
- package executable flasktodo as FlaskTodoWeb in FlaskWebEnv;
110
+ generate TodoWeb in FlaskWebEnv;
@@ -12,5 +12,3 @@ select {
12
12
  dependencies: flask,
13
13
  database: SQLite
14
14
  };
15
-
16
- export FlaskWebEnv;
@@ -12,5 +12,3 @@ select {
12
12
  dependencies: standard library,
13
13
  storage: JSON file
14
14
  };
15
-
16
- export PythonCliEnv;
@@ -66,5 +66,4 @@ realize TodoCli as (
66
66
  main: PythonTodoCli
67
67
  ) in PythonCliEnv;
68
68
 
69
- generate PythonTodoCli;
70
- package executable mytodocli as PythonTodoCli in PythonCliEnv;
69
+ generate TodoCli in PythonCliEnv;
@@ -106,20 +106,3 @@ select {
106
106
  language: TypeScript,
107
107
  runtime: Node.js 20
108
108
  };
109
-
110
- /* Exports for the concrete realizations. */
111
- export TodoId;
112
- export TodoTitle;
113
- export Todo;
114
- export HttpRequest;
115
- export HttpResponse;
116
- export AddTodo;
117
- export ListTodos;
118
- export CompleteTodo;
119
- export TodoApp;
120
- export TodoCli;
121
- export TodoWeb;
122
- export Cli;
123
- export Web;
124
- export Python;
125
- export TypeScript;
@@ -12,5 +12,3 @@ select {
12
12
  dependencies: Node.js standard library,
13
13
  storage: JSON file
14
14
  };
15
-
16
- export TypeScriptCliEnv;
@@ -66,5 +66,4 @@ realize TodoCli as (
66
66
  main: TypeScriptTodoCli
67
67
  ) in TypeScriptCliEnv;
68
68
 
69
- generate TypeScriptTodoCli;
70
- package executable mytotscli as TypeScriptTodoCli in TypeScriptCliEnv;
69
+ generate TodoCli in TypeScriptCliEnv;