@malloydata/malloy-tests 0.0.237-dev250224215546 → 0.0.237-dev250225144145
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.
- package/package.json +9 -8
- package/src/core/dependencies.spec.ts +33 -3
- package/src/core/tags.spec.ts +21 -252
- package/src/util/db-jest-matchers.ts +1 -1
- package/tsconfig.json +6 -0
package/package.json
CHANGED
|
@@ -21,13 +21,14 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@jest/globals": "^29.4.3",
|
|
24
|
-
"@malloydata/db-bigquery": "^0.0.237-
|
|
25
|
-
"@malloydata/db-duckdb": "^0.0.237-
|
|
26
|
-
"@malloydata/db-postgres": "^0.0.237-
|
|
27
|
-
"@malloydata/db-snowflake": "^0.0.237-
|
|
28
|
-
"@malloydata/db-trino": "^0.0.237-
|
|
29
|
-
"@malloydata/malloy": "^0.0.237-
|
|
30
|
-
"@malloydata/
|
|
24
|
+
"@malloydata/db-bigquery": "^0.0.237-dev250225144145",
|
|
25
|
+
"@malloydata/db-duckdb": "^0.0.237-dev250225144145",
|
|
26
|
+
"@malloydata/db-postgres": "^0.0.237-dev250225144145",
|
|
27
|
+
"@malloydata/db-snowflake": "^0.0.237-dev250225144145",
|
|
28
|
+
"@malloydata/db-trino": "^0.0.237-dev250225144145",
|
|
29
|
+
"@malloydata/malloy": "^0.0.237-dev250225144145",
|
|
30
|
+
"@malloydata/malloy-tag": "^0.0.237-dev250225144145",
|
|
31
|
+
"@malloydata/render": "^0.0.237-dev250225144145",
|
|
31
32
|
"events": "^3.3.0",
|
|
32
33
|
"jsdom": "^22.1.0",
|
|
33
34
|
"luxon": "^2.4.0",
|
|
@@ -37,5 +38,5 @@
|
|
|
37
38
|
"@types/jsdom": "^21.1.1",
|
|
38
39
|
"@types/luxon": "^2.4.0"
|
|
39
40
|
},
|
|
40
|
-
"version": "0.0.237-
|
|
41
|
+
"version": "0.0.237-dev250225144145"
|
|
41
42
|
}
|
|
@@ -39,7 +39,13 @@ describe('dependencies', () => {
|
|
|
39
39
|
it('typescript references should not be circular', async () => {
|
|
40
40
|
const deps = await madge('packages', {
|
|
41
41
|
fileExtensions: ['ts'],
|
|
42
|
-
excludeRegExp: [
|
|
42
|
+
excludeRegExp: [
|
|
43
|
+
/malloy\/src\/lang/,
|
|
44
|
+
/malloy-render\/src/,
|
|
45
|
+
/\.d\.ts/,
|
|
46
|
+
/malloy-interfaces\/generated-types/,
|
|
47
|
+
/malloy-tag\/src\/lib/,
|
|
48
|
+
],
|
|
43
49
|
});
|
|
44
50
|
expect(deps.circular().length, getMessage(deps.circular())).toBe(0);
|
|
45
51
|
});
|
|
@@ -55,7 +61,12 @@ describe('dependencies', () => {
|
|
|
55
61
|
it.skip('malloy/src/lang typescript should not be circular', async () => {
|
|
56
62
|
const deps = await madge('packages', {
|
|
57
63
|
fileExtensions: ['ts'],
|
|
58
|
-
excludeRegExp: [
|
|
64
|
+
excludeRegExp: [
|
|
65
|
+
/malloy-render\/src/,
|
|
66
|
+
/\.d\.ts/,
|
|
67
|
+
/malloy-interfaces\/generated-types/,
|
|
68
|
+
/malloy-tag\/src\/lib/,
|
|
69
|
+
],
|
|
59
70
|
});
|
|
60
71
|
expect(deps.circular().length, getMessage(deps.circular())).toBe(0);
|
|
61
72
|
});
|
|
@@ -64,7 +75,26 @@ describe('dependencies', () => {
|
|
|
64
75
|
it.skip('malloy-render/src typescript should not be circular', async () => {
|
|
65
76
|
const deps = await madge('packages', {
|
|
66
77
|
fileExtensions: ['ts'],
|
|
67
|
-
excludeRegExp: [
|
|
78
|
+
excludeRegExp: [
|
|
79
|
+
/malloy\/src\/lang/,
|
|
80
|
+
/\.d\.ts/,
|
|
81
|
+
/malloy-interfaces\/generated-types/,
|
|
82
|
+
/malloy-tag\/src\/lib/,
|
|
83
|
+
],
|
|
84
|
+
});
|
|
85
|
+
expect(deps.circular().length, getMessage(deps.circular())).toBe(0);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// TODO: remove circular references in malloy-tag
|
|
89
|
+
it.skip('malloy-tag/src typescript should not be circular', async () => {
|
|
90
|
+
const deps = await madge('packages', {
|
|
91
|
+
fileExtensions: ['ts'],
|
|
92
|
+
excludeRegExp: [
|
|
93
|
+
/malloy\/src\/lang/,
|
|
94
|
+
/malloy-render\/src/,
|
|
95
|
+
/\.d\.ts/,
|
|
96
|
+
/malloy-interfaces\/generated-types/,
|
|
97
|
+
],
|
|
68
98
|
});
|
|
69
99
|
expect(deps.circular().length, getMessage(deps.circular())).toBe(0);
|
|
70
100
|
});
|
package/src/core/tags.spec.ts
CHANGED
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import {
|
|
24
|
+
import {annotationToTag} from '@malloydata/malloy';
|
|
25
|
+
import {TagDict, Tag} from '@malloydata/malloy-tag';
|
|
25
26
|
import {runtimeFor} from '../runtimes';
|
|
26
27
|
|
|
27
28
|
declare global {
|
|
@@ -36,7 +37,7 @@ declare global {
|
|
|
36
37
|
expect.extend({
|
|
37
38
|
tagsAre(src: string | Tag, result: Tag) {
|
|
38
39
|
if (typeof src === 'string') {
|
|
39
|
-
const {tag, log} = Tag.
|
|
40
|
+
const {tag, log} = Tag.fromTagLine(src, undefined);
|
|
40
41
|
const errs = log.map(e => e.message);
|
|
41
42
|
if (log.length > 0) {
|
|
42
43
|
return {
|
|
@@ -64,243 +65,6 @@ expect.extend({
|
|
|
64
65
|
|
|
65
66
|
const runtime = runtimeFor('duckdb');
|
|
66
67
|
|
|
67
|
-
type TagTestTuple = [string, TagDict];
|
|
68
|
-
describe('tagParse to Tag', () => {
|
|
69
|
-
const tagTests: TagTestTuple[] = [
|
|
70
|
-
['just_name', {just_name: {}}],
|
|
71
|
-
['name=bare_string', {name: {eq: 'bare_string'}}],
|
|
72
|
-
['name="quoted_string"', {name: {eq: 'quoted_string'}}],
|
|
73
|
-
['name {prop1}', {name: {properties: {prop1: {}}}}],
|
|
74
|
-
[
|
|
75
|
-
'name {prop1 prop2=value}',
|
|
76
|
-
{
|
|
77
|
-
name: {
|
|
78
|
-
properties: {
|
|
79
|
-
prop1: {},
|
|
80
|
-
prop2: {eq: 'value'},
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
],
|
|
85
|
-
['name.prop', {name: {properties: {prop: {}}}}],
|
|
86
|
-
['name.prop=value', {name: {properties: {prop: {eq: 'value'}}}}],
|
|
87
|
-
[
|
|
88
|
-
'name.prop.sub=value',
|
|
89
|
-
{name: {properties: {prop: {properties: {sub: {eq: 'value'}}}}}},
|
|
90
|
-
],
|
|
91
|
-
[
|
|
92
|
-
'name{first3=[a, b, c]}',
|
|
93
|
-
{name: {properties: {first3: {eq: [{eq: 'a'}, {eq: 'b'}, {eq: 'c'}]}}}},
|
|
94
|
-
],
|
|
95
|
-
['name{first1=[a,]}', {name: {properties: {first1: {eq: [{eq: 'a'}]}}}}],
|
|
96
|
-
[
|
|
97
|
-
'name{first=[a {A}]}',
|
|
98
|
-
{name: {properties: {first: {eq: [{eq: 'a', properties: {A: {}}}]}}}},
|
|
99
|
-
],
|
|
100
|
-
[
|
|
101
|
-
'name{first=[{A}]}',
|
|
102
|
-
{name: {properties: {first: {eq: [{properties: {A: {}}}]}}}},
|
|
103
|
-
],
|
|
104
|
-
['name=value {prop}', {name: {eq: 'value', properties: {prop: {}}}}],
|
|
105
|
-
[
|
|
106
|
-
'name.prop={prop2}',
|
|
107
|
-
{name: {properties: {prop: {properties: {prop2: {}}}}}},
|
|
108
|
-
],
|
|
109
|
-
['no yes -no', {yes: {}}],
|
|
110
|
-
|
|
111
|
-
// TODO interesting behavior that removing a non-existant element, or the last element,
|
|
112
|
-
// does not remove the `properties`.
|
|
113
|
-
['x -x.y', {x: {properties: {}}}],
|
|
114
|
-
['x={y} -x.y', {x: {properties: {}}}],
|
|
115
|
-
|
|
116
|
-
['x={y z} -x.y', {x: {properties: {z: {}}}}],
|
|
117
|
-
['x={y z} x {-y}', {x: {properties: {z: {}}}}],
|
|
118
|
-
['x=1 x {xx=11}', {x: {eq: '1', properties: {xx: {eq: '11'}}}}],
|
|
119
|
-
['x.y=xx x=1 {...}', {x: {eq: '1', properties: {y: {eq: 'xx'}}}}],
|
|
120
|
-
['a {b c} a=1', {a: {eq: '1'}}],
|
|
121
|
-
['a=1 a=...{b}', {a: {eq: '1', properties: {b: {}}}}],
|
|
122
|
-
[
|
|
123
|
-
'a=red { shade=dark } color=$(a) shade=$(a.shade)',
|
|
124
|
-
{
|
|
125
|
-
a: {eq: 'red', properties: {shade: {eq: 'dark'}}},
|
|
126
|
-
color: {eq: 'red', properties: {shade: {eq: 'dark'}}},
|
|
127
|
-
shade: {eq: 'dark'},
|
|
128
|
-
},
|
|
129
|
-
],
|
|
130
|
-
['x=.01', {x: {eq: '.01'}}],
|
|
131
|
-
['x=-7', {x: {eq: '-7'}}],
|
|
132
|
-
['x=7', {x: {eq: '7'}}],
|
|
133
|
-
['x=7.0', {x: {eq: '7.0'}}],
|
|
134
|
-
['x=.7', {x: {eq: '.7'}}],
|
|
135
|
-
['x=.7e2', {x: {eq: '.7e2'}}],
|
|
136
|
-
['x=7E2', {x: {eq: '7E2'}}],
|
|
137
|
-
['`spacey name`=Zaphod', {'spacey name': {eq: 'Zaphod'}}],
|
|
138
|
-
[
|
|
139
|
-
'image { alt=hello { field=department } }',
|
|
140
|
-
{
|
|
141
|
-
image: {
|
|
142
|
-
properties: {
|
|
143
|
-
alt: {eq: 'hello', properties: {field: {eq: 'department'}}},
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
],
|
|
148
|
-
[
|
|
149
|
-
'image image.alt=hello image.alt.field=department',
|
|
150
|
-
{
|
|
151
|
-
image: {
|
|
152
|
-
properties: {
|
|
153
|
-
alt: {eq: 'hello', properties: {field: {eq: 'department'}}},
|
|
154
|
-
},
|
|
155
|
-
},
|
|
156
|
-
},
|
|
157
|
-
],
|
|
158
|
-
['can remove.properties -...', {}],
|
|
159
|
-
];
|
|
160
|
-
test.each(tagTests)('tag %s', (expression: string, expected: TagDict) => {
|
|
161
|
-
expect(expression).tagsAre(expected);
|
|
162
|
-
});
|
|
163
|
-
test.skip('unskip to debug just one of the expressions', () => {
|
|
164
|
-
const x: TagTestTuple = ['word -...', {}];
|
|
165
|
-
expect(x[0]).tagsAre(x[1]);
|
|
166
|
-
});
|
|
167
|
-
test('inherits can be over-ridden', () => {
|
|
168
|
-
const loc1 = {
|
|
169
|
-
url: 'inherit-test',
|
|
170
|
-
range: {start: {line: 1, character: 0}, end: {line: 1, character: 0}},
|
|
171
|
-
};
|
|
172
|
-
const loc2 = {
|
|
173
|
-
url: 'inherit-test',
|
|
174
|
-
range: {start: {line: 2, character: 0}, end: {line: 2, character: 0}},
|
|
175
|
-
};
|
|
176
|
-
const nestedTags = Tag.annotationToTag({
|
|
177
|
-
inherits: {notes: [{text: '## from=inherits\n', at: loc1}]},
|
|
178
|
-
notes: [{text: '## from=notes\n', at: loc2}],
|
|
179
|
-
});
|
|
180
|
-
const fromVal = nestedTags.tag.text('from');
|
|
181
|
-
expect(fromVal).toEqual('notes');
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
describe('Tag access', () => {
|
|
186
|
-
test('just text', () => {
|
|
187
|
-
const strToParse = 'a=b';
|
|
188
|
-
const getTags = Tag.fromTagline(strToParse, undefined);
|
|
189
|
-
expect(getTags.log).toEqual([]);
|
|
190
|
-
const a = getTags.tag.tag('a');
|
|
191
|
-
expect(a).toBeDefined();
|
|
192
|
-
expect(a?.text()).toEqual('b');
|
|
193
|
-
});
|
|
194
|
-
test('tag path', () => {
|
|
195
|
-
const strToParse = 'a.b.c.d.e=f';
|
|
196
|
-
const tagParse = Tag.fromTagline(strToParse, undefined);
|
|
197
|
-
expect(tagParse.log).toEqual([]);
|
|
198
|
-
const abcde = tagParse.tag.tag('a', 'b', 'c', 'd', 'e');
|
|
199
|
-
expect(abcde).toBeDefined();
|
|
200
|
-
expect(abcde?.text()).toEqual('f');
|
|
201
|
-
});
|
|
202
|
-
test('just array', () => {
|
|
203
|
-
const strToParse = 'a=[b]';
|
|
204
|
-
const getTags = Tag.fromTagline(strToParse, undefined);
|
|
205
|
-
expect(getTags.log).toEqual([]);
|
|
206
|
-
const a = getTags.tag.tag('a');
|
|
207
|
-
const aval = a?.array();
|
|
208
|
-
expect(aval).toBeDefined();
|
|
209
|
-
if (aval) {
|
|
210
|
-
expect(aval.length).toEqual(1);
|
|
211
|
-
expect(aval[0].text()).toEqual('b');
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
test('array as text', () => {
|
|
215
|
-
const strToParse = 'a=[b]';
|
|
216
|
-
const getTags = Tag.fromTagline(strToParse, undefined);
|
|
217
|
-
expect(getTags.log).toEqual([]);
|
|
218
|
-
const a = getTags.tag.tag('a');
|
|
219
|
-
expect(a).toBeDefined();
|
|
220
|
-
expect(a?.text()).toBeUndefined();
|
|
221
|
-
});
|
|
222
|
-
test('text as array', () => {
|
|
223
|
-
const strToParse = 'a=b';
|
|
224
|
-
const getTags = Tag.fromTagline(strToParse, undefined);
|
|
225
|
-
expect(getTags.log).toEqual([]);
|
|
226
|
-
const a = getTags.tag.tag('a');
|
|
227
|
-
expect(a).toBeDefined();
|
|
228
|
-
expect(a?.array()).toBeUndefined();
|
|
229
|
-
});
|
|
230
|
-
test('just numeric', () => {
|
|
231
|
-
const strToParse = 'a=7';
|
|
232
|
-
const getTags = Tag.fromTagline(strToParse, undefined);
|
|
233
|
-
expect(getTags.log).toEqual([]);
|
|
234
|
-
const a = getTags.tag.tag('a');
|
|
235
|
-
expect(a).toBeDefined();
|
|
236
|
-
const n = a?.numeric();
|
|
237
|
-
expect(typeof n).toBe('number');
|
|
238
|
-
expect(n).toEqual(7);
|
|
239
|
-
});
|
|
240
|
-
test('text as numeric', () => {
|
|
241
|
-
const strToParse = 'a=seven';
|
|
242
|
-
const getTags = Tag.fromTagline(strToParse, undefined);
|
|
243
|
-
expect(getTags.log).toEqual([]);
|
|
244
|
-
const a = getTags.tag.tag('a');
|
|
245
|
-
expect(a).toBeDefined();
|
|
246
|
-
const n = a?.numeric();
|
|
247
|
-
expect(n).toBeUndefined();
|
|
248
|
-
});
|
|
249
|
-
test('array as numeric', () => {
|
|
250
|
-
const strToParse = 'a=[seven]';
|
|
251
|
-
const getTags = Tag.fromTagline(strToParse, undefined);
|
|
252
|
-
expect(getTags.log).toEqual([]);
|
|
253
|
-
const a = getTags.tag.tag('a');
|
|
254
|
-
expect(a).toBeDefined();
|
|
255
|
-
const n = a?.numeric();
|
|
256
|
-
expect(n).toBeUndefined();
|
|
257
|
-
});
|
|
258
|
-
test('full text array', () => {
|
|
259
|
-
const strToParse = 'a=[b,c]';
|
|
260
|
-
const getTags = Tag.fromTagline(strToParse, undefined);
|
|
261
|
-
expect(getTags.log).toEqual([]);
|
|
262
|
-
const a = getTags.tag.tag('a');
|
|
263
|
-
expect(a).toBeDefined();
|
|
264
|
-
const ais = a?.textArray();
|
|
265
|
-
expect(ais).toEqual(['b', 'c']);
|
|
266
|
-
});
|
|
267
|
-
test('filtered text array', () => {
|
|
268
|
-
const strToParse = 'a=[b,c,{d}]';
|
|
269
|
-
const getTags = Tag.fromTagline(strToParse, undefined);
|
|
270
|
-
expect(getTags.log).toEqual([]);
|
|
271
|
-
const a = getTags.tag.tag('a');
|
|
272
|
-
expect(a).toBeDefined();
|
|
273
|
-
const ais = a?.textArray();
|
|
274
|
-
expect(ais).toEqual(['b', 'c']);
|
|
275
|
-
});
|
|
276
|
-
test('full numeric array', () => {
|
|
277
|
-
const strToParse = 'a=[1,2]';
|
|
278
|
-
const getTags = Tag.fromTagline(strToParse, undefined);
|
|
279
|
-
expect(getTags.log).toEqual([]);
|
|
280
|
-
const a = getTags.tag.tag('a');
|
|
281
|
-
expect(a).toBeDefined();
|
|
282
|
-
const ais = a?.numericArray();
|
|
283
|
-
expect(ais).toEqual([1, 2]);
|
|
284
|
-
});
|
|
285
|
-
test('filtered numeric array', () => {
|
|
286
|
-
const strToParse = 'a=[1,2,three]';
|
|
287
|
-
const getTags = Tag.fromTagline(strToParse, undefined);
|
|
288
|
-
expect(getTags.log).toEqual([]);
|
|
289
|
-
const a = getTags.tag.tag('a');
|
|
290
|
-
expect(a).toBeDefined();
|
|
291
|
-
const ais = a?.numericArray();
|
|
292
|
-
expect(ais).toEqual([1, 2]);
|
|
293
|
-
});
|
|
294
|
-
test('has', () => {
|
|
295
|
-
const strToParse = 'a b.d';
|
|
296
|
-
const getTags = Tag.fromTagline(strToParse, undefined);
|
|
297
|
-
expect(getTags.log).toEqual([]);
|
|
298
|
-
expect(getTags.tag.has('a')).toBeTruthy();
|
|
299
|
-
expect(getTags.tag.has('b', 'd')).toBeTruthy();
|
|
300
|
-
expect(getTags.tag.has('c')).toBeFalsy();
|
|
301
|
-
});
|
|
302
|
-
});
|
|
303
|
-
|
|
304
68
|
describe('## top level', () => {
|
|
305
69
|
test('top level tags are available in the model def', async () => {
|
|
306
70
|
const model = await runtime
|
|
@@ -495,10 +259,10 @@ describe('tags in results', () => {
|
|
|
495
259
|
expect(field).toBeDefined();
|
|
496
260
|
let tp = field.tagParse().tag;
|
|
497
261
|
expect(tp).tagsAre({valueFrom: {eq: 'model'}});
|
|
498
|
-
const sessionScope = Tag.
|
|
262
|
+
const sessionScope = Tag.fromTagLine('# scope=session', undefined).tag;
|
|
499
263
|
tp = field.tagParse({scopes: [sessionScope]}).tag;
|
|
500
264
|
expect(tp).tagsAre({valueFrom: {eq: 'session'}});
|
|
501
|
-
const globalScope = Tag.
|
|
265
|
+
const globalScope = Tag.fromTagLine('# scope=global', undefined).tag;
|
|
502
266
|
tp = field.tagParse({scopes: [globalScope, sessionScope]}).tag;
|
|
503
267
|
expect(tp).tagsAre({valueFrom: {eq: 'global'}});
|
|
504
268
|
});
|
|
@@ -512,17 +276,6 @@ describe('tags in results', () => {
|
|
|
512
276
|
const modelTags = result.modelTag;
|
|
513
277
|
expect(modelTags.text('from')).toEqual('cell2');
|
|
514
278
|
});
|
|
515
|
-
test('property access on existing tag (which does not yet have properties)', () => {
|
|
516
|
-
const parsePlot = Tag.fromTagline('# plot', undefined);
|
|
517
|
-
const parsed = Tag.fromTagline('# plot.x=2', parsePlot.tag);
|
|
518
|
-
const allTags = parsed.tag;
|
|
519
|
-
const plotTag = allTags.tag('plot');
|
|
520
|
-
const xTag = plotTag!.tag('x');
|
|
521
|
-
const x = xTag!.numeric();
|
|
522
|
-
expect(parsed.tag.numeric('plot', 'x')).toEqual(2);
|
|
523
|
-
expect(plotTag!.numeric('x')).toEqual(2);
|
|
524
|
-
expect(x).toEqual(2);
|
|
525
|
-
});
|
|
526
279
|
test('nested fields of same field do not share tags', async () => {
|
|
527
280
|
const loaded = runtime.loadQuery(`
|
|
528
281
|
source: one is duckdb.sql("SELECT 1 as one")
|
|
@@ -548,4 +301,20 @@ describe('tags in results', () => {
|
|
|
548
301
|
});
|
|
549
302
|
}
|
|
550
303
|
});
|
|
304
|
+
test('inherits can be over-ridden', () => {
|
|
305
|
+
const loc1 = {
|
|
306
|
+
url: 'inherit-test',
|
|
307
|
+
range: {start: {line: 1, character: 0}, end: {line: 1, character: 0}},
|
|
308
|
+
};
|
|
309
|
+
const loc2 = {
|
|
310
|
+
url: 'inherit-test',
|
|
311
|
+
range: {start: {line: 2, character: 0}, end: {line: 2, character: 0}},
|
|
312
|
+
};
|
|
313
|
+
const nestedTags = annotationToTag({
|
|
314
|
+
inherits: {notes: [{text: '## from=inherits\n', at: loc1}]},
|
|
315
|
+
notes: [{text: '## from=notes\n', at: loc2}],
|
|
316
|
+
});
|
|
317
|
+
const fromVal = nestedTags.tag.text('from');
|
|
318
|
+
expect(fromVal).toEqual('notes');
|
|
319
|
+
});
|
|
551
320
|
});
|