@malloydata/malloy 0.0.56-dev230710182711 → 0.0.56-dev230710205111
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/index.d.ts +1 -0
- package/dist/lang/ast/index.js +1 -0
- package/dist/lang/ast/query-elements/existing-query.d.ts +3 -3
- package/dist/lang/ast/query-elements/existing-query.js +27 -25
- package/dist/lang/ast/query-elements/full-query.js +12 -0
- package/dist/lang/ast/query-elements/run-query.d.ts +3 -12
- package/dist/lang/ast/query-elements/run-query.js +3 -29
- package/dist/lang/ast/sources/named-source-or-query.d.ts +10 -0
- package/dist/lang/ast/sources/named-source-or-query.js +68 -0
- package/dist/lang/ast/sources/named-source.js +4 -4
- package/dist/lang/ast/types/malloy-element.d.ts +2 -0
- package/dist/lang/ast/types/malloy-element.js +13 -0
- package/dist/lang/lib/Malloy/MalloyLexer.d.ts +100 -98
- package/dist/lang/lib/Malloy/MalloyLexer.js +961 -949
- package/dist/lang/lib/Malloy/MalloyParser.d.ts +359 -272
- package/dist/lang/lib/Malloy/MalloyParser.js +4298 -3762
- package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +218 -100
- package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +135 -61
- package/dist/lang/malloy-to-ast.d.ts +17 -8
- package/dist/lang/malloy-to-ast.js +116 -60
- package/dist/lang/parse-malloy.d.ts +2 -0
- package/dist/lang/parse-malloy.js +2 -0
- package/dist/lang/parse-tree-walkers/document-symbol-walker.js +1 -10
- package/dist/lang/test/document-symbol-walker.spec.js +1 -1
- package/dist/lang/test/parse.spec.js +267 -18
- package/dist/tags.d.ts +1 -0
- package/dist/tags.js +10 -3
- package/package.json +1 -1
|
@@ -52,9 +52,10 @@ describe('model statements', () => {
|
|
|
52
52
|
});
|
|
53
53
|
expect(m).translationToFailWith('a1 is not a connection');
|
|
54
54
|
});
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
test('table function is deprecated', () => {
|
|
56
|
+
expect(`##! m4warnings
|
|
57
|
+
source: testA is table('conn:aTable')
|
|
58
|
+
`).toTranslateWithWarnings("`table('connection_name:table_path')` is deprecated; use `connection_name.table('table_path')`");
|
|
58
59
|
});
|
|
59
60
|
});
|
|
60
61
|
describe('source:', () => {
|
|
@@ -88,13 +89,12 @@ describe('model statements', () => {
|
|
|
88
89
|
});
|
|
89
90
|
});
|
|
90
91
|
describe('query:', () => {
|
|
91
|
-
// Delete this when ENABLE_M4_WARNINGS is converted to an annotation
|
|
92
92
|
test('anonymous query', () => {
|
|
93
93
|
expect((0, test_translator_1.markSource) `query: ${"table('aTable') -> { group_by: astr }"}`).toTranslate();
|
|
94
94
|
});
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
test('anonymous query', () => {
|
|
96
|
+
expect((0, test_translator_1.markSource) `##! m4warnings
|
|
97
|
+
query: ${"conn.table('aTable') -> { group_by: astr }"}`).toTranslateWithWarnings('Anonymous `query:` statements are deprecated, use `run:` instead');
|
|
98
98
|
});
|
|
99
99
|
test('run query', () => expect("run: table('aTable') -> { group_by: astr }").toTranslate());
|
|
100
100
|
test('run query ref', () => expect(`
|
|
@@ -1018,16 +1018,18 @@ describe('qops', () => {
|
|
|
1018
1018
|
expect('query: a -> { extend: { dimension: x is 1; dimension: y is 2; measure: c is count() }; group_by: x, y; aggregate: c }').toTranslate();
|
|
1019
1019
|
});
|
|
1020
1020
|
});
|
|
1021
|
-
|
|
1022
|
-
describe.skip('declare/query join warnings', () => {
|
|
1021
|
+
describe('declare/query join warnings', () => {
|
|
1023
1022
|
test('declare warning in query', () => {
|
|
1024
|
-
expect((0, test_translator_1.markSource)
|
|
1023
|
+
expect((0, test_translator_1.markSource) `##! m4warnings
|
|
1024
|
+
run: a -> { ${'declare: x is 1'}; group_by: x }`).toTranslateWithWarnings('`declare:` is deprecated; use `dimension:` or `measure:` inside a source or `extend:` block');
|
|
1025
1025
|
});
|
|
1026
1026
|
test('declare warning in source', () => {
|
|
1027
|
-
expect((0, test_translator_1.markSource)
|
|
1027
|
+
expect((0, test_translator_1.markSource) `##! m4warnings
|
|
1028
|
+
source: a2 is a extend { ${'declare: x is 1'} }`).toTranslateWithWarnings('`declare:` is deprecated; use `dimension:` or `measure:` inside a source or `extend:` block');
|
|
1028
1029
|
});
|
|
1029
1030
|
test('joins in query', () => {
|
|
1030
|
-
expect((0, test_translator_1.markSource)
|
|
1031
|
+
expect((0, test_translator_1.markSource) `##! m4warnings
|
|
1032
|
+
run: a -> { ${'join_one: b on true'}; ${'join_many: c is b on true'}; ${'join_cross: d is b on true'}; group_by: b.astr }`).toTranslateWithWarnings('Joins in queries are deprecated, move into an `extend:` block.', 'Joins in queries are deprecated, move into an `extend:` block.', 'Joins in queries are deprecated, move into an `extend:` block.');
|
|
1031
1033
|
});
|
|
1032
1034
|
});
|
|
1033
1035
|
test('refine query with extended source', () => {
|
|
@@ -1593,18 +1595,18 @@ describe('error handling', () => {
|
|
|
1593
1595
|
`).translationToFailWith("Cannot redefine 'airports'");
|
|
1594
1596
|
});
|
|
1595
1597
|
test('query from undefined source', () => {
|
|
1596
|
-
expect((0, test_translator_1.markSource) `query: ${'x'}->{ project: y }`).translationToFailWith("Undefined source 'x'");
|
|
1598
|
+
expect((0, test_translator_1.markSource) `query: ${'x'}->{ project: y }`).translationToFailWith("Undefined query or source 'x'");
|
|
1597
1599
|
});
|
|
1598
1600
|
test('query with expression from undefined source', () => {
|
|
1599
1601
|
// Regression check: Once upon a time this died with an exception even
|
|
1600
1602
|
// when "query: x->{ group_by: y}" (above) generated the correct error.
|
|
1601
|
-
expect((0, test_translator_1.markSource) `query: ${'x'}->{ project: y is z / 2 }`).translationToFailWith("Undefined source 'x'");
|
|
1603
|
+
expect((0, test_translator_1.markSource) `query: ${'x'}->{ project: y is z / 2 }`).translationToFailWith("Undefined query or source 'x'");
|
|
1602
1604
|
});
|
|
1603
1605
|
test('join reference before definition', () => {
|
|
1604
1606
|
expect((0, test_translator_1.markSource) `
|
|
1605
1607
|
source: newAB is a { join_one: newB is ${'bb'} on astring }
|
|
1606
1608
|
source: newB is b
|
|
1607
|
-
`).translationToFailWith("Undefined source 'bb'");
|
|
1609
|
+
`).translationToFailWith("Undefined query or source 'bb'");
|
|
1608
1610
|
});
|
|
1609
1611
|
test('non-rename rename', () => {
|
|
1610
1612
|
expect('source: na is a { rename: astr is astr }').translationToFailWith("Can't rename field to itself");
|
|
@@ -2895,9 +2897,9 @@ describe('sql expressions', () => {
|
|
|
2895
2897
|
expect(m).toTranslate();
|
|
2896
2898
|
}
|
|
2897
2899
|
});
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2900
|
+
test('sql statement deprecation warning', () => {
|
|
2901
|
+
const m = new test_translator_1.TestTranslator(`##! m4warnings
|
|
2902
|
+
sql: bad_sql is {select: """SELECT 1 as one"""}`);
|
|
2901
2903
|
const req = m.translate().compileSQL;
|
|
2902
2904
|
if (req) {
|
|
2903
2905
|
m.update({
|
|
@@ -2906,5 +2908,252 @@ describe('sql expressions', () => {
|
|
|
2906
2908
|
}
|
|
2907
2909
|
expect(m).toTranslateWithWarnings('`sql:` statement is deprecated, use `connection_name.sql(...)` instead');
|
|
2908
2910
|
});
|
|
2911
|
+
test('reference to sql expression in run', () => {
|
|
2912
|
+
const m = new test_translator_1.TestTranslator(`
|
|
2913
|
+
run: bigquery.sql("""select 1 as one""")
|
|
2914
|
+
`);
|
|
2915
|
+
expect(m).toParse();
|
|
2916
|
+
const compileSql = m.translate().compileSQL;
|
|
2917
|
+
expect(compileSql).toBeDefined();
|
|
2918
|
+
if (compileSql) {
|
|
2919
|
+
m.update({
|
|
2920
|
+
compileSQL: { [compileSql.name]: getSelectOneStruct(compileSql) },
|
|
2921
|
+
});
|
|
2922
|
+
expect(m).toTranslate();
|
|
2923
|
+
}
|
|
2924
|
+
});
|
|
2925
|
+
test('reference to sql expression in query def', () => {
|
|
2926
|
+
const m = new test_translator_1.TestTranslator(`
|
|
2927
|
+
query: q is bigquery.sql("""select 1 as one""")
|
|
2928
|
+
`);
|
|
2929
|
+
expect(m).toParse();
|
|
2930
|
+
const compileSql = m.translate().compileSQL;
|
|
2931
|
+
expect(compileSql).toBeDefined();
|
|
2932
|
+
if (compileSql) {
|
|
2933
|
+
m.update({
|
|
2934
|
+
compileSQL: { [compileSql.name]: getSelectOneStruct(compileSql) },
|
|
2935
|
+
});
|
|
2936
|
+
expect(m).toTranslate();
|
|
2937
|
+
}
|
|
2938
|
+
});
|
|
2939
|
+
test('reference to sql expression in anonymous query', () => {
|
|
2940
|
+
const m = new test_translator_1.TestTranslator(`
|
|
2941
|
+
query: bigquery.sql("""select 1 as one""")
|
|
2942
|
+
`);
|
|
2943
|
+
expect(m).toParse();
|
|
2944
|
+
const compileSql = m.translate().compileSQL;
|
|
2945
|
+
expect(compileSql).toBeDefined();
|
|
2946
|
+
if (compileSql) {
|
|
2947
|
+
m.update({
|
|
2948
|
+
compileSQL: { [compileSql.name]: getSelectOneStruct(compileSql) },
|
|
2949
|
+
});
|
|
2950
|
+
expect(m).toTranslate();
|
|
2951
|
+
}
|
|
2952
|
+
});
|
|
2953
|
+
// TODO this is not possible to implement yet unless we
|
|
2954
|
+
// can distinguish between the generated IR of `conn.sql(...)`
|
|
2955
|
+
// and `conn.sql(...) -> { project: * }`.
|
|
2956
|
+
test.skip('cannot refine a SQL query', () => {
|
|
2957
|
+
const m = new test_translator_1.TestTranslator(`
|
|
2958
|
+
query: q1 is bigquery.sql("""select 1 as one""")
|
|
2959
|
+
run: q1 refine { where: 1 = 1 }
|
|
2960
|
+
`);
|
|
2961
|
+
expect(m).toParse();
|
|
2962
|
+
const compileSql = m.translate().compileSQL;
|
|
2963
|
+
expect(compileSql).toBeDefined();
|
|
2964
|
+
if (compileSql) {
|
|
2965
|
+
m.update({
|
|
2966
|
+
compileSQL: { [compileSql.name]: getSelectOneStruct(compileSql) },
|
|
2967
|
+
});
|
|
2968
|
+
expect(m).translationToFailWith('Cannot refine a SQL query');
|
|
2969
|
+
}
|
|
2970
|
+
});
|
|
2971
|
+
});
|
|
2972
|
+
describe('extend and refine', () => {
|
|
2973
|
+
describe('extend and refine, new syntax', () => {
|
|
2974
|
+
test('query name with query refinements', () => {
|
|
2975
|
+
expect(`
|
|
2976
|
+
query: q is a -> { group_by: ai }
|
|
2977
|
+
run: q refine { group_by: ai2 is ai }
|
|
2978
|
+
`).toTranslate();
|
|
2979
|
+
});
|
|
2980
|
+
test('query name with source refinements', () => {
|
|
2981
|
+
expect(`
|
|
2982
|
+
query: q is a -> { group_by: ai }
|
|
2983
|
+
source: s is q extend { dimension: ai_2 is ai + ai }
|
|
2984
|
+
`).toTranslate();
|
|
2985
|
+
});
|
|
2986
|
+
test('source name with query refinements', () => {
|
|
2987
|
+
expect('run: a refine { group_by: ai }').translationToFailWith("Illegal reference to 'a', query expected");
|
|
2988
|
+
});
|
|
2989
|
+
test('source name with source refinements', () => {
|
|
2990
|
+
expect('source: s is a extend { dimension: ai_2 is ai + ai }').toTranslate();
|
|
2991
|
+
});
|
|
2992
|
+
test('query with source refinements', () => {
|
|
2993
|
+
expect('source: s is a -> { group_by: ai } extend { dimension: ai_2 is ai + ai }').toTranslate();
|
|
2994
|
+
});
|
|
2995
|
+
test('query with extension then new stage', () => {
|
|
2996
|
+
expect('run: a { dimension: x is 1 } -> { group_by: x }').toTranslate();
|
|
2997
|
+
});
|
|
2998
|
+
});
|
|
2999
|
+
describe('extend and refine, old syntax', () => {
|
|
3000
|
+
test('query name with query refinements', () => {
|
|
3001
|
+
expect(`
|
|
3002
|
+
query: q is a -> { group_by: ai }
|
|
3003
|
+
run: q { group_by: ai2 is ai }
|
|
3004
|
+
`).toTranslate();
|
|
3005
|
+
});
|
|
3006
|
+
test('query name with source refinements', () => {
|
|
3007
|
+
expect(`
|
|
3008
|
+
query: q is a -> { group_by: ai }
|
|
3009
|
+
source: s is q { dimension: ai_2 is ai + ai }
|
|
3010
|
+
`).toTranslate();
|
|
3011
|
+
});
|
|
3012
|
+
test('source name with query refinements', () => {
|
|
3013
|
+
expect('run: a { group_by: one }').translationToFailWith("Illegal reference to 'a', query expected");
|
|
3014
|
+
});
|
|
3015
|
+
test('source name with source refinements', () => {
|
|
3016
|
+
expect('source: s is a { dimension: ai_2 is ai + ai }').toTranslate();
|
|
3017
|
+
});
|
|
3018
|
+
test('source name with ambiguous refinements', () => {
|
|
3019
|
+
// Ambiguous refinements are assumed to be source extensions
|
|
3020
|
+
expect('run: a { join_one: b on b.ai = ai } -> { project: b.* }').toTranslate();
|
|
3021
|
+
expect('run: a { where: 1 = 1 } -> { project: * }').toTranslate();
|
|
3022
|
+
expect('run: a { declare: three is 3 } -> { project: * }').toTranslate();
|
|
3023
|
+
expect('source: s is a { join_one: b on b.ai = ai }').toTranslate();
|
|
3024
|
+
expect('source: s is a { where: 1 = 1 }').toTranslate();
|
|
3025
|
+
expect('source: s is a { declare: three is 3 }').toTranslate();
|
|
3026
|
+
});
|
|
3027
|
+
test('query name with ambiguous refinements', () => {
|
|
3028
|
+
// Here we implicitly convert the query into a source.
|
|
3029
|
+
expect(`
|
|
3030
|
+
query: q is a -> { group_by: ai }
|
|
3031
|
+
run: q { join_one: b on 1 = 1 } -> { project: b.* }
|
|
3032
|
+
`).toTranslate();
|
|
3033
|
+
expect(`
|
|
3034
|
+
query: q is a -> { group_by: ai }
|
|
3035
|
+
run: q { where: 1 = 1 } -> { project: * }
|
|
3036
|
+
`).toTranslate();
|
|
3037
|
+
expect(`
|
|
3038
|
+
query: q is a -> { group_by: ai }
|
|
3039
|
+
run: q { declare: three is 3 } -> { project: * }
|
|
3040
|
+
`).toTranslate();
|
|
3041
|
+
// Without the new stage we automatically recognize this as a query refinement
|
|
3042
|
+
expect(`
|
|
3043
|
+
query: q is a -> { group_by: ai }
|
|
3044
|
+
run: q { join_one: b on 1 = 1 }
|
|
3045
|
+
`).toTranslate();
|
|
3046
|
+
expect(`
|
|
3047
|
+
query: q is a -> { group_by: ai }
|
|
3048
|
+
run: q { where: 1 = 1 }
|
|
3049
|
+
`).toTranslate();
|
|
3050
|
+
expect(`
|
|
3051
|
+
query: q is a -> { group_by: ai }
|
|
3052
|
+
run: q { declare: three is 3 }
|
|
3053
|
+
`).toTranslate();
|
|
3054
|
+
// Can also just add from() to use as a source
|
|
3055
|
+
// TODO add a warning when you use from() -- "`from()` is deprecated; to apply source extensions to a query, use `extend`"
|
|
3056
|
+
expect(`
|
|
3057
|
+
query: q is a -> { group_by: ai }
|
|
3058
|
+
source: s is from(q) { join_one: b on b.ai = ai }
|
|
3059
|
+
`).toTranslate();
|
|
3060
|
+
// Can also add an arrow to clarify that it's a query
|
|
3061
|
+
// Of course, number 1 and 3 are actually useless because you're defining
|
|
3062
|
+
// something and then not using it...
|
|
3063
|
+
expect(`
|
|
3064
|
+
query: q is a -> { group_by: ai }
|
|
3065
|
+
run: -> q { join_one: b on b.ai = ai } -> { project: * }
|
|
3066
|
+
`).toTranslate();
|
|
3067
|
+
expect(`
|
|
3068
|
+
query: q is a -> { group_by: ai }
|
|
3069
|
+
run: -> q { where: 1 = 1 } -> { project: * }
|
|
3070
|
+
`).toTranslate();
|
|
3071
|
+
expect(`
|
|
3072
|
+
query: q is a -> { group_by: ai }
|
|
3073
|
+
run: -> q { declare: three is 3 } -> { project: * }
|
|
3074
|
+
`).toTranslate();
|
|
3075
|
+
// Alternatively, fix 1 and 3 by actually using the declared thing
|
|
3076
|
+
expect(`
|
|
3077
|
+
query: q is a -> { group_by: ai }
|
|
3078
|
+
run: q { join_one: b on b.ai = ai; group_by: ai2 is b.ai }
|
|
3079
|
+
`).toTranslate();
|
|
3080
|
+
expect(`
|
|
3081
|
+
query: q is a -> { group_by: ai }
|
|
3082
|
+
run: q { declare: three is 3; group_by: three }
|
|
3083
|
+
`).toTranslate();
|
|
3084
|
+
});
|
|
3085
|
+
});
|
|
3086
|
+
describe('extend and refine fallout', () => {
|
|
3087
|
+
test('syntactically valid to run a source, but still illegal', () => {
|
|
3088
|
+
expect('run: a').translationToFailWith("Illegal reference to 'a', query expected");
|
|
3089
|
+
});
|
|
3090
|
+
test('syntactically valid to refine a source, but illegal', () => {
|
|
3091
|
+
expect('run: a { group_by: ai } ').translationToFailWith("Illegal reference to 'a', query expected");
|
|
3092
|
+
expect('run: a refine { group_by: ai } ').translationToFailWith("Illegal reference to 'a', query expected");
|
|
3093
|
+
});
|
|
3094
|
+
});
|
|
3095
|
+
describe('turtles', () => {
|
|
3096
|
+
test('explicit refine in turtle works', () => {
|
|
3097
|
+
expect(`source: c is a extend {
|
|
3098
|
+
query: x is { project: * }
|
|
3099
|
+
query: y is x refine { limit: 1 }
|
|
3100
|
+
}`).toTranslate();
|
|
3101
|
+
});
|
|
3102
|
+
test('implicit refine in turtle works', () => {
|
|
3103
|
+
expect(`source: c is a extend {
|
|
3104
|
+
query: x is { project: * }
|
|
3105
|
+
query: y is x { limit: 1 }
|
|
3106
|
+
}`).toTranslate();
|
|
3107
|
+
});
|
|
3108
|
+
});
|
|
3109
|
+
describe('nests', () => {
|
|
3110
|
+
test('explicit refine in nest', () => {
|
|
3111
|
+
expect(`source: c is a extend {
|
|
3112
|
+
query: x is { project: * }
|
|
3113
|
+
}
|
|
3114
|
+
|
|
3115
|
+
run: c -> {
|
|
3116
|
+
nest: x refine { limit: 1 }
|
|
3117
|
+
}`).toTranslate();
|
|
3118
|
+
});
|
|
3119
|
+
test('implicit refine in nest', () => {
|
|
3120
|
+
expect(`source: c is a extend {
|
|
3121
|
+
query: x is { project: * }
|
|
3122
|
+
}
|
|
3123
|
+
|
|
3124
|
+
run: c -> {
|
|
3125
|
+
nest: x { limit: 1 }
|
|
3126
|
+
}`).toTranslate();
|
|
3127
|
+
});
|
|
3128
|
+
});
|
|
3129
|
+
describe('m4 warnings', () => {
|
|
3130
|
+
test('implicit refine in nest', () => {
|
|
3131
|
+
expect(`##! m4warnings
|
|
3132
|
+
source: c is a extend {
|
|
3133
|
+
query: x is { project: * }
|
|
3134
|
+
}
|
|
3135
|
+
|
|
3136
|
+
run: c -> {
|
|
3137
|
+
nest: x { limit: 1 }
|
|
3138
|
+
}`).toTranslateWithWarnings('Implicit query refinement is deprecated, use the `refine` operator.');
|
|
3139
|
+
});
|
|
3140
|
+
test('implicit refine in turtle works', () => {
|
|
3141
|
+
expect(`##! m4warnings
|
|
3142
|
+
source: c is a extend {
|
|
3143
|
+
query: x is { project: * }
|
|
3144
|
+
query: y is x { limit: 1 }
|
|
3145
|
+
}`).toTranslateWithWarnings('Implicit query refinement is deprecated, use the `refine` operator.');
|
|
3146
|
+
});
|
|
3147
|
+
test('implicit query refinement', () => {
|
|
3148
|
+
expect(`##! m4warnings
|
|
3149
|
+
query: q is a -> { group_by: ai }
|
|
3150
|
+
run: q { group_by: three is 3 }
|
|
3151
|
+
`).toTranslateWithWarnings('Implicit query refinement is deprecated, use the `refine` operator.');
|
|
3152
|
+
});
|
|
3153
|
+
test('implicit source extension', () => {
|
|
3154
|
+
expect(`##! m4warnings
|
|
3155
|
+
source: s is a { dimension: ai_2 is ai + ai }`).toTranslateWithWarnings('Implicit source extension is deprecated, use the `extend` operator.');
|
|
3156
|
+
});
|
|
3157
|
+
});
|
|
2909
3158
|
});
|
|
2910
3159
|
//# sourceMappingURL=parse.spec.js.map
|
package/dist/tags.d.ts
CHANGED
package/dist/tags.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.Tags = void 0;
|
|
25
|
+
exports.parseTagProperties = exports.Tags = void 0;
|
|
26
26
|
function isDocTag(a) {
|
|
27
27
|
return (a === null || a === void 0 ? void 0 : a.docString) !== undefined;
|
|
28
28
|
}
|
|
@@ -79,6 +79,12 @@ function parseTag(src, tagProp) {
|
|
|
79
79
|
if (!propMatch) {
|
|
80
80
|
return;
|
|
81
81
|
}
|
|
82
|
+
const newProps = parseTagProperties(src.slice(propMatch[0].length), tagProp);
|
|
83
|
+
if (newProps) {
|
|
84
|
+
return { properties: newProps };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function parseTagProperties(src, tagProp) {
|
|
82
88
|
/*
|
|
83
89
|
* I went back and forth if the grammar for these annotations should be
|
|
84
90
|
* in the parser or the lexer. Eventually the fact that the lexer ate
|
|
@@ -86,7 +92,7 @@ function parseTag(src, tagProp) {
|
|
|
86
92
|
*
|
|
87
93
|
* Seems wrong to be writing a parser though.
|
|
88
94
|
*/
|
|
89
|
-
const tokens = tokenize(src
|
|
95
|
+
const tokens = tokenize(src);
|
|
90
96
|
let tn = 0;
|
|
91
97
|
const lastToken = tokens.length - 1;
|
|
92
98
|
while (tn <= lastToken) {
|
|
@@ -119,8 +125,9 @@ function parseTag(src, tagProp) {
|
|
|
119
125
|
}
|
|
120
126
|
tn += 1;
|
|
121
127
|
}
|
|
122
|
-
return
|
|
128
|
+
return tagProp;
|
|
123
129
|
}
|
|
130
|
+
exports.parseTagProperties = parseTagProperties;
|
|
124
131
|
function tokenize(src) {
|
|
125
132
|
const parts = [];
|
|
126
133
|
src = src.trim();
|