@malloydata/malloy 0.0.28-dev230314211807 → 0.0.28-dev230320190215
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/dist/lang/ast/elements/define-query.js +1 -1
- package/dist/lang/ast/elements/import-statement.js +2 -6
- package/dist/lang/ast/query-elements/existing-query.d.ts +1 -1
- package/dist/lang/ast/query-elements/existing-query.js +3 -3
- package/dist/lang/ast/query-elements/full-query.d.ts +1 -1
- package/dist/lang/ast/query-elements/full-query.js +5 -3
- package/dist/lang/ast/sources/query-source.js +1 -1
- package/dist/lang/parse-malloy.d.ts +6 -2
- package/dist/lang/parse-malloy.js +3 -2
- package/dist/lang/test/imports.spec.d.ts +1 -0
- package/dist/lang/test/imports.spec.js +160 -0
- package/dist/lang/test/parse-expects.d.ts +14 -0
- package/dist/lang/test/parse-expects.js +232 -0
- package/dist/lang/test/parse.spec.d.ts +1 -14
- package/dist/lang/test/parse.spec.js +83 -459
- package/dist/lang/test/test-translator.d.ts +21 -3
- package/dist/lang/test/test-translator.js +105 -7
- package/package.json +1 -1
|
@@ -56,12 +56,8 @@ class ImportStatement extends malloy_element_1.MalloyElement {
|
|
|
56
56
|
if (childNeeds) {
|
|
57
57
|
return childNeeds;
|
|
58
58
|
}
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
doc.setEntry(importing, {
|
|
62
|
-
entry: importStructs[importing],
|
|
63
|
-
exported: false,
|
|
64
|
-
});
|
|
59
|
+
for (const [importing, entry] of Object.entries(trans.getChildExports(this.fullURL))) {
|
|
60
|
+
doc.setEntry(importing, { entry, exported: false });
|
|
65
61
|
}
|
|
66
62
|
}
|
|
67
63
|
else if (src.status === 'error') {
|
|
@@ -6,6 +6,6 @@ export declare class ExistingQuery extends PipelineDesc {
|
|
|
6
6
|
_head?: ModelEntryReference;
|
|
7
7
|
set head(head: ModelEntryReference | undefined);
|
|
8
8
|
get head(): ModelEntryReference | undefined;
|
|
9
|
-
queryComp(): QueryComp;
|
|
9
|
+
queryComp(isRefOk: boolean): QueryComp;
|
|
10
10
|
query(): Query;
|
|
11
11
|
}
|
|
@@ -35,7 +35,7 @@ class ExistingQuery extends pipeline_desc_1.PipelineDesc {
|
|
|
35
35
|
get head() {
|
|
36
36
|
return this._head;
|
|
37
37
|
}
|
|
38
|
-
queryComp() {
|
|
38
|
+
queryComp(isRefOk) {
|
|
39
39
|
if (!this.head) {
|
|
40
40
|
throw this.internalError("can't make query from nameless query");
|
|
41
41
|
}
|
|
@@ -66,13 +66,13 @@ class ExistingQuery extends pipeline_desc_1.PipelineDesc {
|
|
|
66
66
|
const query = {
|
|
67
67
|
type: 'query',
|
|
68
68
|
...destPipe,
|
|
69
|
-
structRef: queryHead.structRef(),
|
|
69
|
+
structRef: isRefOk ? queryHead.structRef() : queryHead.structDef(),
|
|
70
70
|
location: this.location,
|
|
71
71
|
};
|
|
72
72
|
return { outputStruct: appended.structDef, query };
|
|
73
73
|
}
|
|
74
74
|
query() {
|
|
75
|
-
return this.queryComp().query;
|
|
75
|
+
return this.queryComp(true).query;
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
exports.ExistingQuery = ExistingQuery;
|
|
@@ -5,6 +5,6 @@ import { TurtleHeadedPipe } from '../types/turtle-headed-pipe';
|
|
|
5
5
|
export declare class FullQuery extends TurtleHeadedPipe {
|
|
6
6
|
readonly explore: Source;
|
|
7
7
|
constructor(explore: Source);
|
|
8
|
-
queryComp(): QueryComp;
|
|
8
|
+
queryComp(isRefOk: boolean): QueryComp;
|
|
9
9
|
query(): Query;
|
|
10
10
|
}
|
|
@@ -32,8 +32,10 @@ class FullQuery extends turtle_headed_pipe_1.TurtleHeadedPipe {
|
|
|
32
32
|
super({ explore: explore });
|
|
33
33
|
this.explore = explore;
|
|
34
34
|
}
|
|
35
|
-
queryComp() {
|
|
36
|
-
const structRef =
|
|
35
|
+
queryComp(isRefOk) {
|
|
36
|
+
const structRef = isRefOk
|
|
37
|
+
? this.explore.structRef()
|
|
38
|
+
: this.explore.structDef();
|
|
37
39
|
const destQuery = {
|
|
38
40
|
type: 'query',
|
|
39
41
|
structRef,
|
|
@@ -78,7 +80,7 @@ class FullQuery extends turtle_headed_pipe_1.TurtleHeadedPipe {
|
|
|
78
80
|
return { outputStruct: appended.structDef, query: destQuery };
|
|
79
81
|
}
|
|
80
82
|
query() {
|
|
81
|
-
return this.queryComp().query;
|
|
83
|
+
return this.queryComp(true).query;
|
|
82
84
|
}
|
|
83
85
|
}
|
|
84
86
|
exports.FullQuery = FullQuery;
|
|
@@ -31,7 +31,7 @@ class QuerySource extends source_1.Source {
|
|
|
31
31
|
this.elementType = 'querySource';
|
|
32
32
|
}
|
|
33
33
|
structDef() {
|
|
34
|
-
const comp = this.query.queryComp();
|
|
34
|
+
const comp = this.query.queryComp(false);
|
|
35
35
|
const queryStruct = comp.outputStruct;
|
|
36
36
|
queryStruct.structSource = { type: 'query', query: comp.query };
|
|
37
37
|
return queryStruct;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CodePointCharStream, CommonTokenStream, ParserRuleContext, Token } from 'antlr4ts';
|
|
2
2
|
import { ParseTree } from 'antlr4ts/tree';
|
|
3
|
-
import { DocumentLocation, DocumentPosition, DocumentRange, DocumentReference, ModelDef,
|
|
3
|
+
import { DocumentLocation, DocumentPosition, DocumentRange, DocumentReference, ModelDef, NamedModelObject, Query, SQLBlockStructDef, StructDef } from '../model/malloy_types';
|
|
4
4
|
import { MessageLog } from './parse-log';
|
|
5
5
|
import { Zone, ZoneData } from './zone';
|
|
6
6
|
import { ReferenceList } from './reference-list';
|
|
@@ -125,7 +125,7 @@ export declare abstract class MalloyTranslation {
|
|
|
125
125
|
getLineMap(url: string): string[] | undefined;
|
|
126
126
|
prettyErrors(): string;
|
|
127
127
|
childRequest(importURL: string): ModelDataRequest;
|
|
128
|
-
getChildExports(importURL: string):
|
|
128
|
+
getChildExports(importURL: string): Record<string, NamedModelObject>;
|
|
129
129
|
private finalAnswer?;
|
|
130
130
|
translate(extendingModel?: ModelDef): TranslateResponse;
|
|
131
131
|
metadata(): MetadataResponse;
|
|
@@ -142,6 +142,10 @@ export declare abstract class MalloyTranslation {
|
|
|
142
142
|
rangeFromTokens(startToken: Token, stopToken: Token): DocumentRange;
|
|
143
143
|
rangeFromToken(token: Token): DocumentRange;
|
|
144
144
|
}
|
|
145
|
+
export declare class MalloyChildTranslator extends MalloyTranslation {
|
|
146
|
+
readonly root: MalloyTranslator;
|
|
147
|
+
constructor(rootURL: string, root: MalloyTranslator);
|
|
148
|
+
}
|
|
145
149
|
/**
|
|
146
150
|
* The main interface to Malloy tranlsation. It has a call pattern
|
|
147
151
|
* similar to a server. Once a translator is instantiated
|
|
@@ -45,7 +45,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
45
45
|
return result;
|
|
46
46
|
};
|
|
47
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
-
exports.MalloyTranslator = exports.MalloyTranslation = void 0;
|
|
48
|
+
exports.MalloyTranslator = exports.MalloyChildTranslator = exports.MalloyTranslation = void 0;
|
|
49
49
|
const antlr4ts_1 = require("antlr4ts");
|
|
50
50
|
const MalloyLexer_1 = require("./lib/Malloy/MalloyLexer");
|
|
51
51
|
const MalloyParser_1 = require("./lib/Malloy/MalloyParser");
|
|
@@ -612,7 +612,7 @@ class MalloyTranslation {
|
|
|
612
612
|
if (did.translated) {
|
|
613
613
|
for (const fromChild of child.modelDef.exports) {
|
|
614
614
|
const modelEntry = child.modelDef.contents[fromChild];
|
|
615
|
-
if (modelEntry.type === 'struct') {
|
|
615
|
+
if (modelEntry.type === 'struct' || modelEntry.type === 'query') {
|
|
616
616
|
exports[fromChild] = modelEntry;
|
|
617
617
|
}
|
|
618
618
|
}
|
|
@@ -695,6 +695,7 @@ class MalloyChildTranslator extends MalloyTranslation {
|
|
|
695
695
|
this.root = root;
|
|
696
696
|
}
|
|
697
697
|
}
|
|
698
|
+
exports.MalloyChildTranslator = MalloyChildTranslator;
|
|
698
699
|
/**
|
|
699
700
|
* The main interface to Malloy tranlsation. It has a call pattern
|
|
700
701
|
* similar to a server. Once a translator is instantiated
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import './parse-expects';
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/*
|
|
4
|
+
* Copyright 2023 Google LLC
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining
|
|
7
|
+
* a copy of this software and associated documentation files
|
|
8
|
+
* (the "Software"), to deal in the Software without restriction,
|
|
9
|
+
* including without limitation the rights to use, copy, modify, merge,
|
|
10
|
+
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
11
|
+
* and to permit persons to whom the Software is furnished to do so,
|
|
12
|
+
* subject to the following conditions:
|
|
13
|
+
*
|
|
14
|
+
* The above copyright notice and this permission notice shall be
|
|
15
|
+
* included in all copies or substantial portions of the Software.
|
|
16
|
+
*
|
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
18
|
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
19
|
+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
20
|
+
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
21
|
+
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
22
|
+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
23
|
+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
24
|
+
*/
|
|
25
|
+
require("./parse-expects");
|
|
26
|
+
const test_translator_1 = require("./test-translator");
|
|
27
|
+
describe('import:', () => {
|
|
28
|
+
test('simple source', () => {
|
|
29
|
+
const docParse = new test_translator_1.TestTranslator('import "child"');
|
|
30
|
+
const xr = docParse.unresolved();
|
|
31
|
+
expect(docParse).toBeErrorless();
|
|
32
|
+
expect(xr).toEqual({ urls: ['internal://test/langtests/child'] });
|
|
33
|
+
docParse.update({
|
|
34
|
+
urls: { 'internal://test/langtests/child': 'source: aa is a' },
|
|
35
|
+
});
|
|
36
|
+
expect(docParse).modelCompiled();
|
|
37
|
+
const aa = docParse.getSourceDef('aa');
|
|
38
|
+
expect(aa).toBeDefined();
|
|
39
|
+
});
|
|
40
|
+
test('simple query', () => {
|
|
41
|
+
const docParse = new test_translator_1.TestTranslator('import "child"');
|
|
42
|
+
const xr = docParse.unresolved();
|
|
43
|
+
expect(docParse).toBeErrorless();
|
|
44
|
+
expect(xr).toEqual({ urls: ['internal://test/langtests/child'] });
|
|
45
|
+
docParse.update({
|
|
46
|
+
urls: {
|
|
47
|
+
'internal://test/langtests/child': 'query: aq is a->{ project: * }',
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
expect(docParse).modelCompiled();
|
|
51
|
+
const aq = docParse.getQuery('aq');
|
|
52
|
+
expect(aq).toBeDefined();
|
|
53
|
+
});
|
|
54
|
+
test('query based source with named structref', () => {
|
|
55
|
+
const docParse = new test_translator_1.TestTranslator(`
|
|
56
|
+
import "child"
|
|
57
|
+
source: newSrc is a {
|
|
58
|
+
join_one: b is botProjQSrc on b.astr = astr
|
|
59
|
+
}
|
|
60
|
+
`);
|
|
61
|
+
const xr = docParse.unresolved();
|
|
62
|
+
expect(docParse).toBeErrorless();
|
|
63
|
+
expect(xr).toEqual({ urls: ['internal://test/langtests/child'] });
|
|
64
|
+
docParse.update({
|
|
65
|
+
urls: {
|
|
66
|
+
'internal://test/langtests/child': `
|
|
67
|
+
source: bottomSrc is a
|
|
68
|
+
query: botProjQ is bottomSrc -> { project: * }
|
|
69
|
+
source: botProjQSrc is from(->botProjQ)
|
|
70
|
+
`,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
expect(docParse).modelCompiled();
|
|
74
|
+
const newSrc = docParse.getSourceDef('newSrc');
|
|
75
|
+
const f = newSrc === null || newSrc === void 0 ? void 0 : newSrc.fields.find(f => f.name === 'b');
|
|
76
|
+
expect(f === null || f === void 0 ? void 0 : f.type).toBe('struct');
|
|
77
|
+
if ((f === null || f === void 0 ? void 0 : f.type) === 'struct') {
|
|
78
|
+
const ss = f.structSource;
|
|
79
|
+
expect(ss.type).toBe('query');
|
|
80
|
+
if (ss.type === 'query') {
|
|
81
|
+
expect(typeof ss.query.structRef).not.toBe('string');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
test('missing import', () => {
|
|
86
|
+
const docParse = new test_translator_1.TestTranslator('import "child"');
|
|
87
|
+
const xr = docParse.unresolved();
|
|
88
|
+
expect(docParse).toBeErrorless();
|
|
89
|
+
expect(xr).toEqual({ urls: ['internal://test/langtests/child'] });
|
|
90
|
+
const reportedError = 'ENOWAY: No way to find your child';
|
|
91
|
+
docParse.update({
|
|
92
|
+
errors: {
|
|
93
|
+
urls: { 'internal://test/langtests/child': reportedError },
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
docParse.translate();
|
|
97
|
+
expect(docParse).not.toBeErrorless();
|
|
98
|
+
expect(docParse.prettyErrors()).toContain(reportedError);
|
|
99
|
+
});
|
|
100
|
+
test('chained imports', () => {
|
|
101
|
+
const docParse = new test_translator_1.TestTranslator('import "child"');
|
|
102
|
+
docParse.update({
|
|
103
|
+
urls: { 'internal://test/langtests/child': 'import "grandChild"' },
|
|
104
|
+
});
|
|
105
|
+
const xr = docParse.unresolved();
|
|
106
|
+
expect(docParse).toBeErrorless();
|
|
107
|
+
expect(xr).toEqual({ urls: ['internal://test/langtests/grandChild'] });
|
|
108
|
+
});
|
|
109
|
+
test('relative imports', () => {
|
|
110
|
+
const docParse = new test_translator_1.TestTranslator('import "../parent.malloy"');
|
|
111
|
+
expect(docParse).modelParsed();
|
|
112
|
+
const xr = docParse.unresolved();
|
|
113
|
+
expect(xr).toEqual({ urls: ['internal://test/parent.malloy'] });
|
|
114
|
+
docParse.update({
|
|
115
|
+
urls: {
|
|
116
|
+
'internal://test/parent.malloy': "source: aa is table('aTable')",
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
expect(docParse).modelCompiled();
|
|
120
|
+
});
|
|
121
|
+
test('relative imports with errors', () => {
|
|
122
|
+
const docParse = new test_translator_1.TestTranslator('import "../parent.malloy"');
|
|
123
|
+
expect(docParse).modelParsed();
|
|
124
|
+
const xr = docParse.unresolved();
|
|
125
|
+
expect(xr).toEqual({ urls: ['internal://test/parent.malloy'] });
|
|
126
|
+
docParse.update({
|
|
127
|
+
urls: {
|
|
128
|
+
'internal://test/parent.malloy': `
|
|
129
|
+
source: aa is table('aTable') {
|
|
130
|
+
dimension: astr is 'not legal beause astr exists'
|
|
131
|
+
}`,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
expect(docParse).compileToFailWith("Cannot redefine 'astr'");
|
|
135
|
+
});
|
|
136
|
+
test('source references expanded when not exported', () => {
|
|
137
|
+
const srcFiles = {
|
|
138
|
+
'internal://test/langtests/middle': `
|
|
139
|
+
import "bottom"
|
|
140
|
+
source: midSrc is from(bottomSrc -> { group_by: astr })
|
|
141
|
+
`,
|
|
142
|
+
'internal://test/langtests/bottom': "source: bottomSrc is table('aTable')",
|
|
143
|
+
};
|
|
144
|
+
const fullModel = new test_translator_1.TestTranslator(`
|
|
145
|
+
import "middle"
|
|
146
|
+
`);
|
|
147
|
+
fullModel.update({ urls: srcFiles });
|
|
148
|
+
expect(fullModel).modelCompiled();
|
|
149
|
+
const ms = fullModel.getSourceDef('midSrc');
|
|
150
|
+
expect(ms).toBeDefined();
|
|
151
|
+
if (ms) {
|
|
152
|
+
expect(ms.structSource.type).toBe('query');
|
|
153
|
+
if (ms.structSource.type === 'query') {
|
|
154
|
+
const qs = ms.structSource.query.structRef;
|
|
155
|
+
expect(typeof qs).not.toBe('string');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
//# sourceMappingURL=imports.spec.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DocumentLocation } from '../../model';
|
|
2
|
+
declare global {
|
|
3
|
+
namespace jest {
|
|
4
|
+
interface Matchers<R> {
|
|
5
|
+
modelParsed(): R;
|
|
6
|
+
toBeErrorless(): R;
|
|
7
|
+
toCompile(): R;
|
|
8
|
+
modelCompiled(): R;
|
|
9
|
+
toReturnType(tp: string): R;
|
|
10
|
+
compileToFailWith(...expectedErrors: string[]): R;
|
|
11
|
+
isLocationIn(at: DocumentLocation, txt: string): R;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable no-console */
|
|
3
|
+
/*
|
|
4
|
+
* Copyright 2023 Google LLC
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining
|
|
7
|
+
* a copy of this software and associated documentation files
|
|
8
|
+
* (the "Software"), to deal in the Software without restriction,
|
|
9
|
+
* including without limitation the rights to use, copy, modify, merge,
|
|
10
|
+
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
11
|
+
* and to permit persons to whom the Software is furnished to do so,
|
|
12
|
+
* subject to the following conditions:
|
|
13
|
+
*
|
|
14
|
+
* The above copyright notice and this permission notice shall be
|
|
15
|
+
* included in all copies or substantial portions of the Software.
|
|
16
|
+
*
|
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
18
|
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
19
|
+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
20
|
+
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
21
|
+
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
22
|
+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
23
|
+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
const test_translator_1 = require("./test-translator");
|
|
27
|
+
const util_1 = require("util");
|
|
28
|
+
function checkForErrors(trans) {
|
|
29
|
+
if (trans.logger === undefined) {
|
|
30
|
+
throw new Error('JESTERY BROKEN, CANT FIND ERORR LOG');
|
|
31
|
+
}
|
|
32
|
+
if (trans.logger.hasErrors()) {
|
|
33
|
+
return {
|
|
34
|
+
message: () => `Translation Errors:\n${trans.prettyErrors()}`,
|
|
35
|
+
pass: false,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
message: () => 'Unexpected error free translation',
|
|
40
|
+
pass: true,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function prettyNeeds(response) {
|
|
44
|
+
let needString = '';
|
|
45
|
+
if (response.tables) {
|
|
46
|
+
needString += 'Tables:\n';
|
|
47
|
+
response.tables.forEach(table => (needString += ` - ${table}`));
|
|
48
|
+
}
|
|
49
|
+
if (response.compileSQL) {
|
|
50
|
+
needString += `Compile SQL: ${response.compileSQL.name}`;
|
|
51
|
+
}
|
|
52
|
+
if (response.urls) {
|
|
53
|
+
needString += 'URLs:\n';
|
|
54
|
+
response.urls.forEach(url => (needString += ` - ${url}`));
|
|
55
|
+
}
|
|
56
|
+
return needString;
|
|
57
|
+
}
|
|
58
|
+
function checkForNeededs(trans) {
|
|
59
|
+
const response = trans.translateStep.step(trans);
|
|
60
|
+
if (!response.final) {
|
|
61
|
+
return {
|
|
62
|
+
message: () => `Translation is not complete, needs:\n${prettyNeeds(response)}`,
|
|
63
|
+
pass: false,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
message: () => 'Unexpected complete translation',
|
|
68
|
+
pass: true,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function highlightError(dl, txt) {
|
|
72
|
+
if (dl === undefined) {
|
|
73
|
+
return '~Location Undefined~';
|
|
74
|
+
}
|
|
75
|
+
const { start, end } = dl.range;
|
|
76
|
+
const output = [
|
|
77
|
+
`${start.line}:${start.character}-${end.line}:${end.character}`,
|
|
78
|
+
];
|
|
79
|
+
let errStart = start.character;
|
|
80
|
+
const doc = txt.split('\n');
|
|
81
|
+
for (let line = start.line; line <= end.line; line += 1) {
|
|
82
|
+
const lineText = doc[line];
|
|
83
|
+
const lineStr = ` ${line}`.slice(-5);
|
|
84
|
+
output.push(`${lineStr}| ${lineText}`);
|
|
85
|
+
const upToError = ' | ' + ' '.repeat(errStart);
|
|
86
|
+
let errLen = end.character - errStart;
|
|
87
|
+
if (line < end.line) {
|
|
88
|
+
errLen = lineText.length - errStart;
|
|
89
|
+
errStart = 0;
|
|
90
|
+
}
|
|
91
|
+
output.push(upToError + '-'.repeat(errLen));
|
|
92
|
+
}
|
|
93
|
+
return output.join('\n');
|
|
94
|
+
}
|
|
95
|
+
expect.extend({
|
|
96
|
+
toCompile: function (s) {
|
|
97
|
+
const x = new test_translator_1.TestTranslator(s);
|
|
98
|
+
x.compile();
|
|
99
|
+
const errorCheck = checkForErrors(x);
|
|
100
|
+
if (!errorCheck.pass) {
|
|
101
|
+
return errorCheck;
|
|
102
|
+
}
|
|
103
|
+
x.translate();
|
|
104
|
+
return checkForNeededs(x);
|
|
105
|
+
},
|
|
106
|
+
modelParsed: function (x) {
|
|
107
|
+
x.compile();
|
|
108
|
+
return checkForErrors(x);
|
|
109
|
+
},
|
|
110
|
+
modelCompiled: function (x) {
|
|
111
|
+
x.compile();
|
|
112
|
+
const errorCheck = checkForErrors(x);
|
|
113
|
+
if (!errorCheck.pass) {
|
|
114
|
+
return errorCheck;
|
|
115
|
+
}
|
|
116
|
+
x.translate();
|
|
117
|
+
return checkForNeededs(x);
|
|
118
|
+
},
|
|
119
|
+
toBeErrorless: function (trans) {
|
|
120
|
+
return checkForErrors(trans);
|
|
121
|
+
},
|
|
122
|
+
toReturnType: function (functionCall, returnType) {
|
|
123
|
+
const exprModel = new test_translator_1.TestTranslator(`explore: x is a { dimension: d is ${functionCall} }`);
|
|
124
|
+
expect(exprModel).modelCompiled();
|
|
125
|
+
const x = exprModel.getSourceDef('x');
|
|
126
|
+
expect(x).toBeDefined();
|
|
127
|
+
if (x) {
|
|
128
|
+
const d = x.fields.find(f => f.name === 'd');
|
|
129
|
+
expect(d === null || d === void 0 ? void 0 : d.type).toBe(returnType);
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
pass: true,
|
|
133
|
+
message: () => '',
|
|
134
|
+
};
|
|
135
|
+
},
|
|
136
|
+
compileToFailWith: function (s, ...msgs) {
|
|
137
|
+
var _a;
|
|
138
|
+
let emsg = 'Compile Error expectation not met\nExpected error';
|
|
139
|
+
let mSrc;
|
|
140
|
+
const qmsgs = msgs.map(s => `error '${s}'`);
|
|
141
|
+
if (msgs.length === 1) {
|
|
142
|
+
emsg += ` ${qmsgs[0]}`;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
emsg += `s [\n${qmsgs.join('\n')}\n]`;
|
|
146
|
+
}
|
|
147
|
+
let m;
|
|
148
|
+
let src;
|
|
149
|
+
if (s instanceof test_translator_1.TestTranslator) {
|
|
150
|
+
m = s;
|
|
151
|
+
src = m.testSrc;
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
if (typeof s === 'string') {
|
|
155
|
+
src = s;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
src = s.code;
|
|
159
|
+
mSrc = s;
|
|
160
|
+
}
|
|
161
|
+
m = new test_translator_1.TestTranslator(src);
|
|
162
|
+
}
|
|
163
|
+
emsg += `\nSource:\n${src}`;
|
|
164
|
+
const t = m.translate();
|
|
165
|
+
if (t.translated) {
|
|
166
|
+
return { pass: false, message: () => emsg };
|
|
167
|
+
}
|
|
168
|
+
else if (t.errors === undefined) {
|
|
169
|
+
return {
|
|
170
|
+
pass: false,
|
|
171
|
+
message: () => 'TEST ERROR, not all objects resolved in source\n' +
|
|
172
|
+
(0, test_translator_1.pretty)(t) +
|
|
173
|
+
'\n' +
|
|
174
|
+
emsg,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
const explain = [];
|
|
179
|
+
const errList = m.errors().errors;
|
|
180
|
+
let i;
|
|
181
|
+
for (i = 0; i < msgs.length && errList[i]; i += 1) {
|
|
182
|
+
const msg = msgs[i];
|
|
183
|
+
const err = errList[i];
|
|
184
|
+
if (msg !== err.message) {
|
|
185
|
+
explain.push(`Expected: ${msg}\nGot: ${err.message}`);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
if (mSrc === null || mSrc === void 0 ? void 0 : mSrc.locations[i]) {
|
|
189
|
+
const have = (_a = err.at) === null || _a === void 0 ? void 0 : _a.range;
|
|
190
|
+
const want = mSrc.locations[i].range;
|
|
191
|
+
if (!this.equals(have, want)) {
|
|
192
|
+
explain.push(`Expected '${msg}' at location: ${(0, util_1.inspect)(want)}\n` +
|
|
193
|
+
`Actual location: ${(0, util_1.inspect)(have)}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (i !== msgs.length) {
|
|
199
|
+
explain.push(...msgs.slice(i).map(m => `Missing: ${m}`));
|
|
200
|
+
}
|
|
201
|
+
if (i !== errList.length) {
|
|
202
|
+
explain.push(...errList.slice(i).map(m => `Unexpected Error: ${m.message}`));
|
|
203
|
+
}
|
|
204
|
+
if (explain.length === 0) {
|
|
205
|
+
return {
|
|
206
|
+
pass: true,
|
|
207
|
+
message: () => `All expected errors found: ${(0, test_translator_1.pretty)(msgs)}`,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
pass: false,
|
|
212
|
+
message: () => `Compiler did not generated expected errors\n${explain.join('\n')}`,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
isLocationIn: function (checkAt, at, text) {
|
|
217
|
+
if (this.equals(at, checkAt)) {
|
|
218
|
+
return {
|
|
219
|
+
pass: true,
|
|
220
|
+
message: () => 'Locations match',
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
const errMsg = 'Locations do not match\n' +
|
|
224
|
+
`Expected: ${highlightError(at, text)}\n` +
|
|
225
|
+
`Received: ${highlightError(checkAt, text)}\n`;
|
|
226
|
+
return {
|
|
227
|
+
pass: false,
|
|
228
|
+
message: () => errMsg,
|
|
229
|
+
};
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
//# sourceMappingURL=parse-expects.js.map
|
|
@@ -1,14 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
declare global {
|
|
3
|
-
namespace jest {
|
|
4
|
-
interface Matchers<R> {
|
|
5
|
-
modelParsed(): R;
|
|
6
|
-
toBeErrorless(): R;
|
|
7
|
-
toCompile(): R;
|
|
8
|
-
modelCompiled(): R;
|
|
9
|
-
toReturnType(tp: string): R;
|
|
10
|
-
compileToFailWith(...expectedErrors: string[]): R;
|
|
11
|
-
isLocationIn(at: DocumentLocation, txt: string): R;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
1
|
+
import './parse-expects';
|