@voxgig/create-sdkgen 0.23.0 → 0.25.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.
- package/dist/create-sdkgen.js +0 -20
- package/dist/create-sdkgen.js.map +1 -1
- package/dist/project/standard/CreateRoot.js +1 -103
- package/dist/project/standard/CreateRoot.js.map +1 -1
- package/package.json +3 -3
- package/project/standard/.sdk/admin/README.md +38 -3
- package/project/standard/.sdk/admin/check-drift.sh +97 -0
- package/project/standard/.sdk/model/config.aon +0 -5
- package/project/standard/.sdk/model/sdk.fragment.aon +1 -6
- package/project/standard/.sdk/package.json +6 -5
- package/project/standard/.sdk/src/BuildSDK.ts +5 -22
- package/project/standard/.sdk/src/Root.ts +0 -22
- package/project/standard/.sdk/src/Top.ts +0 -8
- package/project/standard/.sdk/test/feature/cost.aon +0 -43
- package/project/standard/.sdk/test/primary/clean.aon +0 -7
- package/project/standard/.sdk/test/primary/featureAdd.aon +0 -11
- package/project/standard/.sdk/test/primary/featureHook.aon +0 -10
- package/project/standard/.sdk/test/primary/featureInit.aon +0 -10
- package/project/standard/.sdk/test/primary/fetcher.aon +0 -10
- package/project/standard/.sdk/test/primary/makeFetchDef.aon +0 -10
- package/project/standard/.sdk/test/primary/makePoint.aon +0 -22
- package/project/standard/.sdk/test/primary/makeResult.aon +0 -14
- package/project/standard/.sdk/test/primary/prepareAuth.aon +0 -5
- package/project/standard/.sdk/test/primary/preparePath.aon +0 -7
- package/project/standard/.sdk/test/struct/nullsem.aon +2 -95
- package/project/standard/.sdk/test/struct/select.aon +79 -96
- package/src/create-sdkgen.ts +0 -35
- package/src/project/standard/CreateRoot.ts +1 -103
|
@@ -2,41 +2,39 @@
|
|
|
2
2
|
basic: {
|
|
3
3
|
set: [
|
|
4
4
|
# Basic equality matching
|
|
5
|
-
{ in: { query: {age:30}, obj: {a:{name:'Alice',age:30}, b:{name:'Bob',age:25}} },
|
|
5
|
+
{ in: { query: {age:30}, obj: {a:{name:'Alice',age:30}, b:{name:'Bob',age:25}} },
|
|
6
6
|
out: [{name:'Alice',age:30,'$KEY':'a'}] }
|
|
7
7
|
|
|
8
|
-
{ in: { query: {name:'Bob'}, obj: {a:{name:'Alice',age:30}, b:{name:'Bob',age:25}} },
|
|
8
|
+
{ in: { query: {name:'Bob'}, obj: {a:{name:'Alice',age:30}, b:{name:'Bob',age:25}} },
|
|
9
9
|
out: [{name:'Bob',age:25,'$KEY':'b'}] }
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
# Multiple field equality
|
|
12
|
-
{ in: { query: {age:30,city:'NYC'}, obj: {a:{age:30,city:'NYC'}, b:{age:30,city:'LA'}} },
|
|
12
|
+
{ in: { query: {age:30,city:'NYC'}, obj: {a:{age:30,city:'NYC'}, b:{age:30,city:'LA'}} },
|
|
13
13
|
out: [{age:30,city:'NYC','$KEY':'a'}] }
|
|
14
|
-
|
|
15
|
-
# Array children
|
|
14
|
+
|
|
16
15
|
{ in: { query: {type:'user'},
|
|
17
|
-
obj: [{id:1,type:'user'}, {id:2,type:'admin'}, {id:3,type:'user'}] },
|
|
16
|
+
obj: [{id:1,type:'user'}, {id:2,type:'admin'}, {id:3,type:'user'}] },
|
|
18
17
|
out: [{id:1,type:'user','$KEY':0}, {id:3,type:'user','$KEY':2}] }
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
{ in: { query: {age:40}, obj: {a:{age:30}, b:{age:25}} },
|
|
18
|
+
|
|
19
|
+
{ in: { query: {age:40}, obj: {a:{age:30}, b:{age:25}} },
|
|
22
20
|
out: [] }
|
|
23
|
-
|
|
21
|
+
|
|
24
22
|
# Empty query matches all
|
|
25
|
-
{ in: { query: {}, obj: {a:{x:1}, b:{x:2}} },
|
|
23
|
+
{ in: { query: {}, obj: {a:{x:1}, b:{x:2}} },
|
|
26
24
|
out: [{x:1,'$KEY':'a'}, {x:2,'$KEY':'b'}] }
|
|
27
|
-
|
|
25
|
+
|
|
28
26
|
# Non-object input
|
|
29
27
|
{ in: { query: {x:1}, obj: 'hello' }, out: [] }
|
|
30
28
|
{ in: { query: {x:1}, obj: 42 }, out: [] }
|
|
31
29
|
{ in: { query: {x:1}, obj: null }, out: [] }
|
|
32
30
|
{ in: { query: {x:1}, obj: undefined }, out: [] }
|
|
33
|
-
|
|
31
|
+
|
|
34
32
|
# Deep equality for objects
|
|
35
|
-
{ in: { query: {data:{x:1,y:2}}, obj: {a:{data:{x:1,y:2}}, b:{data:{x:1,y:3}}} },
|
|
33
|
+
{ in: { query: {data:{x:1,y:2}}, obj: {a:{data:{x:1,y:2}}, b:{data:{x:1,y:3}}} },
|
|
36
34
|
out: [{data:{x:1,y:2},'$KEY':'a'}] }
|
|
37
|
-
|
|
35
|
+
|
|
38
36
|
# Deep equality for arrays
|
|
39
|
-
{ in: { query: {tags:['a','b']}, obj: {a:{tags:['a','b']}, b:{tags:['a','c']}} },
|
|
37
|
+
{ in: { query: {tags:['a','b']}, obj: {a:{tags:['a','b']}, b:{tags:['a','c']}} },
|
|
40
38
|
out: [{tags:['a','b'],'$KEY':'a'}] }
|
|
41
39
|
]
|
|
42
40
|
}
|
|
@@ -44,156 +42,141 @@ basic: {
|
|
|
44
42
|
operators: {
|
|
45
43
|
set: [
|
|
46
44
|
# `$AND` operator
|
|
47
|
-
{ in: { query: {'`$AND`':[{age:30}, {city:'NYC'}]},
|
|
48
|
-
obj: {a:{age:30,city:'NYC'}, b:{age:30,city:'LA'}, c:{age:25,city:'NYC'}} },
|
|
45
|
+
{ in: { query: {'`$AND`':[{age:30}, {city:'NYC'}]},
|
|
46
|
+
obj: {a:{age:30,city:'NYC'}, b:{age:30,city:'LA'}, c:{age:25,city:'NYC'}} },
|
|
49
47
|
out: [{age:30,city:'NYC','$KEY':'a'}] }
|
|
50
|
-
|
|
48
|
+
|
|
51
49
|
# `$AND` with no matches
|
|
52
|
-
{ in: { query: {'`$AND`':[{age:30}, {city:'Boston'}]},
|
|
53
|
-
obj: {a:{age:30,city:'NYC'}, b:{age:30,city:'LA'}} },
|
|
50
|
+
{ in: { query: {'`$AND`':[{age:30}, {city:'Boston'}]},
|
|
51
|
+
obj: {a:{age:30,city:'NYC'}, b:{age:30,city:'LA'}} },
|
|
54
52
|
out: [] }
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
obj: {a:'x', b:'z', c:'y'} },
|
|
53
|
+
|
|
54
|
+
{ in: { query: {'`$OR`':['x', 'y']},
|
|
55
|
+
obj: {a:'x', b:'z', c:'y'} },
|
|
59
56
|
out: ['x', 'y'] }
|
|
60
57
|
|
|
61
58
|
|
|
62
|
-
# TODO: review
|
|
63
|
-
|
|
64
|
-
# { in: { query: {'$KEY':{'`$OR`':['b', 'c']}},
|
|
65
|
-
# obj: {a:'x', b:'z', c:'y'} },
|
|
66
|
-
# out: ['z', 'y'] }
|
|
67
59
|
|
|
68
|
-
# { in: { query: {'`$OR`':[{'$KEY':'b'}, {'$KEY':'c'}]},
|
|
69
|
-
# obj: {a:'x', b:'z', c:'y'} },
|
|
70
|
-
# out: ['z', 'y'] }
|
|
71
60
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
{ in: { query: {'`$OR`':[{age:25}, {age:35}]},
|
|
64
|
+
obj: {a:{age:30}, b:{age:25}, c:{age:35}} },
|
|
75
65
|
out: [{age:25,'$KEY':'b'}, {age:35,'$KEY':'c'}] }
|
|
76
|
-
|
|
66
|
+
|
|
77
67
|
# `$OR` with all matches
|
|
78
|
-
{ in: { query: {'`$OR`':[{type:'user'}, {type:'admin'}]},
|
|
79
|
-
obj: [{type:'user'}, {type:'admin'}, {type:'guest'}] },
|
|
68
|
+
{ in: { query: {'`$OR`':[{type:'user'}, {type:'admin'}]},
|
|
69
|
+
obj: [{type:'user'}, {type:'admin'}, {type:'guest'}] },
|
|
80
70
|
out: [{type:'user','$KEY':0}, {type:'admin','$KEY':1}] }
|
|
81
|
-
|
|
71
|
+
|
|
82
72
|
# Nested `$AND` within `$OR`
|
|
83
|
-
{ in: { query: {'`$OR`':[{'`$AND`':[{role:'user'}, {active:true}]}, {'`$AND`':[{role:'admin'}, {age:30}]}]},
|
|
84
|
-
obj: {a:{role:'admin',age:30,active:true}, b:{role:'user',age:25,active:true},
|
|
85
|
-
c:{role:'user',age:30,active:false}, d:{role:'admin',age:30,active:false}} },
|
|
86
|
-
out: [{role:'admin',age:30,active:true,'$KEY':'a'}, {role:'user',age:25,active:true,'$KEY':'b'},
|
|
73
|
+
{ in: { query: {'`$OR`':[{'`$AND`':[{role:'user'}, {active:true}]}, {'`$AND`':[{role:'admin'}, {age:30}]}]},
|
|
74
|
+
obj: {a:{role:'admin',age:30,active:true}, b:{role:'user',age:25,active:true},
|
|
75
|
+
c:{role:'user',age:30,active:false}, d:{role:'admin',age:30,active:false}} },
|
|
76
|
+
out: [{role:'admin',age:30,active:true,'$KEY':'a'}, {role:'user',age:25,active:true,'$KEY':'b'},
|
|
87
77
|
{role:'admin',age:30,active:false,'$KEY':'d'}] }
|
|
88
|
-
|
|
78
|
+
|
|
89
79
|
# Complex nested operators
|
|
90
|
-
{ in: { query: {'`$AND`':[{'`$OR`':[{status:'active'}, {status:'pending'}]}, {priority:'high'}]},
|
|
91
|
-
obj: {a:{status:'active',priority:'high'}, b:{status:'active',priority:'low'},
|
|
92
|
-
c:{status:'pending',priority:'high'}, d:{status:'done',priority:'high'}} },
|
|
80
|
+
{ in: { query: {'`$AND`':[{'`$OR`':[{status:'active'}, {status:'pending'}]}, {priority:'high'}]},
|
|
81
|
+
obj: {a:{status:'active',priority:'high'}, b:{status:'active',priority:'low'},
|
|
82
|
+
c:{status:'pending',priority:'high'}, d:{status:'done',priority:'high'}} },
|
|
93
83
|
out: [{status:'active',priority:'high','$KEY':'a'}, {status:'pending',priority:'high','$KEY':'c'}] }
|
|
94
|
-
|
|
84
|
+
|
|
95
85
|
# Empty `$AND` array (should match all)
|
|
96
|
-
{ in: { query: {'`$AND`':[]}, obj: {a:{x:1}, b:{x:2}} },
|
|
86
|
+
{ in: { query: {'`$AND`':[]}, obj: {a:{x:1}, b:{x:2}} },
|
|
97
87
|
out: [{x:1,'$KEY':'a'}, {x:2,'$KEY':'b'}] }
|
|
98
|
-
|
|
88
|
+
|
|
99
89
|
# Empty `$OR` array (should match none)
|
|
100
|
-
{ in: { query: {'`$OR`':[]}, obj: {a:{x:1}, b:{x:2}} },
|
|
90
|
+
{ in: { query: {'`$OR`':[]}, obj: {a:{x:1}, b:{x:2}} },
|
|
101
91
|
out: [] }
|
|
102
92
|
|
|
103
93
|
|
|
104
|
-
{ in: { query: {a:{'`$GT`':10}}, obj: [{a:9},{a:10},{a:11},{a:12}] },
|
|
94
|
+
{ in: { query: {a:{'`$GT`':10}}, obj: [{a:9},{a:10},{a:11},{a:12}] },
|
|
105
95
|
out: [{a:11,'$KEY':2},{a:12,'$KEY':3}] }
|
|
106
96
|
|
|
107
|
-
{ in: { query: {a:{'`$GTE`':10}}, obj: [{a:9},{a:10},{a:11},{a:12}] },
|
|
97
|
+
{ in: { query: {a:{'`$GTE`':10}}, obj: [{a:9},{a:10},{a:11},{a:12}] },
|
|
108
98
|
out: [{a:10,'$KEY':1},{a:11,'$KEY':2},{a:12,'$KEY':3}] }
|
|
109
99
|
|
|
110
|
-
|
|
111
|
-
{ in: { query: {b:{'`$LT`':10}}, obj: [{b:9},{b:10},{b:11},{b:12}] },
|
|
100
|
+
|
|
101
|
+
{ in: { query: {b:{'`$LT`':10}}, obj: [{b:9},{b:10},{b:11},{b:12}] },
|
|
112
102
|
out: [{b:9,'$KEY':0}] }
|
|
113
103
|
|
|
114
|
-
{ in: { query: {b:{'`$LTE`':10}}, obj: [{b:9},{b:10},{b:11},{b:12}] },
|
|
104
|
+
{ in: { query: {b:{'`$LTE`':10}}, obj: [{b:9},{b:10},{b:11},{b:12}] },
|
|
115
105
|
out: [{b:9,'$KEY':0},{b:10,'$KEY':1}] }
|
|
116
106
|
|
|
117
|
-
|
|
118
|
-
{ in: { query: {a:b:'`$LT`':10}, obj: [{a:b:9},{a:b:10},{a:b:11},{a:b:12}] },
|
|
107
|
+
|
|
108
|
+
{ in: { query: {a:b:'`$LT`':10}, obj: [{a:b:9},{a:b:10},{a:b:11},{a:b:12}] },
|
|
119
109
|
out: [{a:b:9,'$KEY':0}] }
|
|
120
110
|
|
|
121
|
-
|
|
122
|
-
{ in: { query: {x:{y:20}}, obj: [{x:{y:20,z:220}},{x:{y:21,z:221}}] },
|
|
111
|
+
|
|
112
|
+
{ in: { query: {x:{y:20}}, obj: [{x:{y:20,z:220}},{x:{y:21,z:221}}] },
|
|
123
113
|
out: [{x:{y:20,z:220},'$KEY':0}] }
|
|
124
114
|
|
|
125
|
-
{ in: { query: {s0:'`$LIKE`':'[aA][bB][cC]'}, obj: [{s0:'DEf'},{s0:'ABc'}] },
|
|
115
|
+
{ in: { query: {s0:'`$LIKE`':'[aA][bB][cC]'}, obj: [{s0:'DEf'},{s0:'ABc'}] },
|
|
126
116
|
out: [{s0:'ABc','$KEY':1}] }
|
|
127
117
|
|
|
128
118
|
|
|
129
|
-
{ in: { query: {'`$NOT`':10}, obj: [9,10,11] },
|
|
119
|
+
{ in: { query: {'`$NOT`':10}, obj: [9,10,11] },
|
|
130
120
|
out: [9,11] }
|
|
131
121
|
|
|
132
|
-
{ in: { query: {'`$NOT`':{n0:'x'}}, obj: [{n0:x},{n0:y},{n0:z}] },
|
|
122
|
+
{ in: { query: {'`$NOT`':{n0:'x'}}, obj: [{n0:x},{n0:y},{n0:z}] },
|
|
133
123
|
out: [{n0:y,'$KEY':1},{n0:z,'$KEY':2}] }
|
|
134
124
|
|
|
135
125
|
{ in: { query: {'`$NOT`':{'`$OR`':[{x:1},{y:2}]}},
|
|
136
|
-
obj: [{x:1,y:3},{x:2,y:2},{x:3,y:1}] },
|
|
126
|
+
obj: [{x:1,y:3},{x:2,y:2},{x:3,y:1}] },
|
|
137
127
|
out: [{x:3,y:1,'$KEY':2}] }
|
|
138
|
-
|
|
128
|
+
|
|
139
129
|
]
|
|
140
130
|
}
|
|
141
131
|
|
|
142
132
|
edge: {
|
|
143
133
|
set: [
|
|
144
134
|
# Mixed equality and operators
|
|
145
|
-
{ in: { query: {type:'user', '`$OR`':[{status:'active'}, {admin:true}]},
|
|
146
|
-
obj: [{type:'user',status:'active'}, {type:'user',status:'inactive',admin:true},
|
|
147
|
-
{type:'guest',status:'active'}] },
|
|
135
|
+
{ in: { query: {type:'user', '`$OR`':[{status:'active'}, {admin:true}]},
|
|
136
|
+
obj: [{type:'user',status:'active'}, {type:'user',status:'inactive',admin:true},
|
|
137
|
+
{type:'guest',status:'active'}] },
|
|
148
138
|
out: [{type:'user',status:'active','$KEY':0}, {type:'user',status:'inactive',admin:true,'$KEY':1}] }
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
{ in: { query: {value:q}, obj: {a:{value:q}, b:{value:p},c:{}} },
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
{ in: { query: {value:q}, obj: {a:{value:q}, b:{value:p},c:{}} },
|
|
152
142
|
out: [{value:q,'$KEY':'a'}] }
|
|
153
143
|
|
|
154
|
-
{ in: { query: {value:null}, obj: {a:{value:null}, b:{value:0}, c:{}} },
|
|
144
|
+
{ in: { query: {value:null}, obj: {a:{value:null}, b:{value:0}, c:{}} },
|
|
155
145
|
out: [{value:null,'$KEY':'a'}] }
|
|
156
|
-
|
|
157
|
-
{ in: { query: {active:true}, obj: {a:{active:true}, b:{active:false}, c:{active:1}} },
|
|
146
|
+
|
|
147
|
+
{ in: { query: {active:true}, obj: {a:{active:true}, b:{active:false}, c:{active:1}} },
|
|
158
148
|
out: [{active:true,'$KEY':'a'}] }
|
|
159
|
-
|
|
149
|
+
|
|
160
150
|
# Number comparison (exact match)
|
|
161
|
-
{ in: { query: {count:0}, obj: {a:{count:0}, b:{count:false}, c:{count:'0'}} },
|
|
151
|
+
{ in: { query: {count:0}, obj: {a:{count:0}, b:{count:false}, c:{count:'0'}} },
|
|
162
152
|
out: [{count:0,'$KEY':'a'}] }
|
|
163
153
|
|
|
164
|
-
|
|
165
|
-
{ in: { query: {'`$OR`':[{a:1},{a:2}]}, obj: [{a:0}, {a:1}, {a:2}, {a:3}] },
|
|
154
|
+
|
|
155
|
+
{ in: { query: {'`$OR`':[{a:1},{a:2}]}, obj: [{a:0}, {a:1}, {a:2}, {a:3}] },
|
|
166
156
|
out: [{a:1,'$KEY':1}, {a:2,'$KEY':2}] }
|
|
167
157
|
|
|
168
|
-
{ in: { query: {a:{'`$OR`':[10,20]}}, obj: [{a:0}, {a:10}, {a:20}, {a:30}] },
|
|
158
|
+
{ in: { query: {a:{'`$OR`':[10,20]}}, obj: [{a:0}, {a:10}, {a:20}, {a:30}] },
|
|
169
159
|
out: [{a:10,'$KEY':1}, {a:20,'$KEY':2}] }
|
|
170
160
|
|
|
171
161
|
{ in: { query: {a2:{'`$OR`':[{b2:1},{b2:2}]}},
|
|
172
|
-
obj: [{a2:{b2:0}}, {a2:{b2:1}}, {a2:{b2:2}}, {a2:{b2:3}}] },
|
|
162
|
+
obj: [{a2:{b2:0}}, {a2:{b2:1}}, {a2:{b2:2}}, {a2:{b2:3}}] },
|
|
173
163
|
out: [{a2:{b2:1},'$KEY':1}, {a2:{b2:2},'$KEY':2}] }
|
|
174
164
|
|
|
175
|
-
{ in: { query: {'`$OR`':[{a3:{'`$OR`':[1]}}]}, obj: [{a3:0}, {a3:1}, {a3:2}] },
|
|
165
|
+
{ in: { query: {'`$OR`':[{a3:{'`$OR`':[1]}}]}, obj: [{a3:0}, {a3:1}, {a3:2}] },
|
|
176
166
|
out: [{a3:1,'$KEY':1}] }
|
|
177
167
|
|
|
178
168
|
|
|
179
169
|
{ in: { query: {c0:{'`$AND`':[{x:1},{y:2}]}},
|
|
180
|
-
obj: [{c0:{x:1,y:3,z:0}}, {c0:{x:1,y:2,z:1}}] },
|
|
170
|
+
obj: [{c0:{x:1,y:3,z:0}}, {c0:{x:1,y:2,z:1}}] },
|
|
181
171
|
out: [{c0:{x:1,y:2,z:1},'$KEY':1}] }
|
|
182
172
|
|
|
183
173
|
{ in: { query: {c0:{'`$AND`':[{x:1},{y:{'`$OR`':[2,3]}}]}},
|
|
184
|
-
obj: [{c0:{x:1,y:3,z:0}}, {c0:{x:1,y:2,z:1}}, {c0:{x:1,y:1,z:2}}] },
|
|
185
|
-
out: [{c0:{x:1,y:3,z:0},'$KEY':0}, {c0:{x:1,y:2,z:1},'$KEY':1}] }
|
|
174
|
+
obj: [{c0:{x:1,y:3,z:0}}, {c0:{x:1,y:2,z:1}}, {c0:{x:1,y:1,z:2}}] },
|
|
175
|
+
out: [{c0:{x:1,y:3,z:0},'$KEY':0}, {c0:{x:1,y:2,z:1},'$KEY':1}] }
|
|
186
176
|
]
|
|
187
177
|
}
|
|
188
178
|
|
|
189
179
|
|
|
190
|
-
# path alternates selection
|
|
191
|
-
# NOTES FOR SDK:
|
|
192
|
-
# build query by union of all select keys, getting values from operation spec, match
|
|
193
|
-
# need a deterministic sort of alts so multiple selects (should not happen) have at least
|
|
194
|
-
# a stable list of returned alts order. also $path as get out of jail
|
|
195
|
-
# normalize: /a/{x}/b/ -> path$:'/a/{}/b'
|
|
196
|
-
# if no alt found, use select to indicate missing select options
|
|
197
180
|
alts: {
|
|
198
181
|
data: obj0: [
|
|
199
182
|
{ select:foo_id:true, x:1 }
|
|
@@ -211,7 +194,7 @@ alts: {
|
|
|
211
194
|
{ select:{'$action':foo,zed_id:true}, x:31 }
|
|
212
195
|
{ select:{'$action':bar,zed_id:true}, x:32 }
|
|
213
196
|
]
|
|
214
|
-
|
|
197
|
+
|
|
215
198
|
set: [
|
|
216
199
|
{ in: { query: select: {
|
|
217
200
|
foo_id:true # boolean true means value exists (incl. JSON null)
|
|
@@ -236,12 +219,12 @@ alts: {
|
|
|
236
219
|
obj: $.struct.select.alts.data.obj2 }
|
|
237
220
|
out: [{ '$KEY': 0, select: { query:q0:v0 }, x: 21} ]
|
|
238
221
|
}
|
|
239
|
-
|
|
222
|
+
|
|
240
223
|
{ in: { query: select: { '$action':bar, zed_id:true }
|
|
241
224
|
obj: $.struct.select.alts.data.obj3 }
|
|
242
225
|
out: [{ '$KEY': 1, select: {'$action':bar,zed_id:true}, x: 32} ]
|
|
243
226
|
}
|
|
244
|
-
|
|
227
|
+
|
|
245
228
|
|
|
246
229
|
]
|
|
247
230
|
}
|
package/src/create-sdkgen.ts
CHANGED
|
@@ -45,8 +45,6 @@ const { names, Jostraca } = JostracaModule
|
|
|
45
45
|
const SDK_FOLDER = '.sdk'
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
// TODO: CreateSdkGen opts and generate opts should be mostly the same, and
|
|
49
|
-
// generate should override
|
|
50
48
|
function CreateSdkGen(opts: FullCreateSdkGenOptions) {
|
|
51
49
|
const fs = opts.fs || Fs
|
|
52
50
|
|
|
@@ -107,12 +105,6 @@ function CreateSdkGen(opts: FullCreateSdkGenOptions) {
|
|
|
107
105
|
folder,
|
|
108
106
|
log: log.child({ cmp: 'jostraca' }),
|
|
109
107
|
meta: { spec },
|
|
110
|
-
// Overwrite the scaffolded project (.sdk components, templates, build
|
|
111
|
-
// config) rather than 3-way merge. The scaffold is toolchain-derived and
|
|
112
|
-
// not hand-edited; merging against a drifting .jostraca base keeps STALE
|
|
113
|
-
// components/templates on a toolchain bump (so a fix never propagates) and
|
|
114
|
-
// can inject <<<<<<< markers. See @voxgig/sdkgen
|
|
115
|
-
// docs/explanation/regeneration-overwrite.md.
|
|
116
108
|
existing: {
|
|
117
109
|
txt: {
|
|
118
110
|
write: true,
|
|
@@ -166,7 +158,6 @@ function CreateSdkGen(opts: FullCreateSdkGenOptions) {
|
|
|
166
158
|
|
|
167
159
|
projectFolder = Path.resolve(Path.join(__dirname, 'project', spec.project))
|
|
168
160
|
|
|
169
|
-
// TODO: support auto install project npm package (specific version) in a special cache folder
|
|
170
161
|
|
|
171
162
|
if (!fs.existsSync(projectFolder)) {
|
|
172
163
|
projectFolder = spec.project
|
|
@@ -275,17 +266,6 @@ async function installNpm(spec: GenerateSpec, opts: any, model: any) {
|
|
|
275
266
|
await runNpm(['install'], spawn_opts)
|
|
276
267
|
}
|
|
277
268
|
|
|
278
|
-
// `-t` / `-f` are INDEPENDENT of `--no-install`: the documented contract is
|
|
279
|
-
// that --no-install skips `npm install`, not that it drops the requested
|
|
280
|
-
// targets and features. Adding them is still valid without an install when
|
|
281
|
-
// the project already has its toolchain (re-scaffolding an existing folder
|
|
282
|
-
// is a supported flow — "if run against an existing folder generated files
|
|
283
|
-
// will be overwritten").
|
|
284
|
-
//
|
|
285
|
-
// They ARE npm run scripts that resolve @voxgig/sdkgen from node_modules, so
|
|
286
|
-
// without one they cannot work. Fail with an actionable message rather than
|
|
287
|
-
// the raw module-resolution error — and rather than silently skipping, which
|
|
288
|
-
// reports success while leaving config.aon without the requested entries.
|
|
289
269
|
const wanted = [
|
|
290
270
|
(spec.target ?? []).length ? '--target' : '',
|
|
291
271
|
(spec.feature ?? []).length ? '--feature' : '',
|
|
@@ -342,21 +322,6 @@ async function installFeatures(spec: GenerateSpec, opts: any, model: any, spawn_
|
|
|
342
322
|
}
|
|
343
323
|
|
|
344
324
|
|
|
345
|
-
/*
|
|
346
|
-
function logfiles(info: any, log: ReturnType<typeof Pino>) {
|
|
347
|
-
const cwd = process.cwd()
|
|
348
|
-
|
|
349
|
-
; Object.keys(info.files).map(action => {
|
|
350
|
-
let entries = info.files[action]
|
|
351
|
-
if (0 < entries.length) {
|
|
352
|
-
log.debug({
|
|
353
|
-
point: 'file-' + action, entries,
|
|
354
|
-
note: '\n' + entries.map((n: any) => n.replace(cwd, '.')).join('\n')
|
|
355
|
-
})
|
|
356
|
-
}
|
|
357
|
-
})
|
|
358
|
-
}
|
|
359
|
-
*/
|
|
360
325
|
|
|
361
326
|
export type {
|
|
362
327
|
CreateSdkGenOptions,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
3
|
import Path from 'node:path'
|
|
4
|
-
// import * as Fs from 'node:fs'
|
|
5
4
|
|
|
6
5
|
import {
|
|
7
6
|
names,
|
|
@@ -62,39 +61,6 @@ log/
|
|
|
62
61
|
`
|
|
63
62
|
|
|
64
63
|
|
|
65
|
-
// The guide overlay is the ONE model file the user owns.
|
|
66
|
-
//
|
|
67
|
-
// Everything else the scaffold writes is toolchain-derived and is deliberately
|
|
68
|
-
// OVERWRITTEN (see the `existing.txt.write` rationale in create-sdkgen.ts) so a
|
|
69
|
-
// toolchain fix propagates. `model/guide/guide.aon` is the exception: apidef
|
|
70
|
-
// unifies it OVER the heuristic classification, and it is where every
|
|
71
|
-
// documented customization lives — entity rename, hide, move, activate,
|
|
72
|
-
// per-path deactivation, method override, param rename, response transform.
|
|
73
|
-
// Copying the stub over it destroyed that work on every re-scaffold, and
|
|
74
|
-
// cedar-regen.sh re-scaffolds on every regen, so the loss was silent and
|
|
75
|
-
// repeated.
|
|
76
|
-
//
|
|
77
|
-
// It is excluded from the bulk Copy and merged instead (see mergeGuide).
|
|
78
|
-
// The PROJECT overlay: the second model file the user owns.
|
|
79
|
-
//
|
|
80
|
-
// `guide.aon` owns what the API looks like. This owns what the PROJECT is —
|
|
81
|
-
// publication values above all. The sdkgen schema tells you to declare those
|
|
82
|
-
// in `model/sdk.aon` "where they survive a resync", and that was simply not
|
|
83
|
-
// true: ModelSdk rewrites sdk.aon from its template on every scaffold, so a
|
|
84
|
-
// version or package name declared there vanished before the model was built,
|
|
85
|
-
// with no error. The cedar fleet ran for months with every manifest pinned at
|
|
86
|
-
// the schema default 0.0.1 while its git tags climbed past 0.1.1, and this is
|
|
87
|
-
// why.
|
|
88
|
-
//
|
|
89
|
-
// sdk.aon cannot simply be merged the way guide.aon is. Its template owns
|
|
90
|
-
// `name`, `origin` and especially `def` — the OpenAPI filename, which really
|
|
91
|
-
// does change (three cedar specs were renamed in one week). A "keep the user's
|
|
92
|
-
// file" merge would freeze `def` at a spec that no longer exists and break
|
|
93
|
-
// regeneration. So the template keeps sole ownership of sdk.aon, and the
|
|
94
|
-
// user gets a file of their own that sdk.aon includes.
|
|
95
|
-
//
|
|
96
|
-
// Written ONCE. If it exists, it is re-emitted byte-for-byte, so a
|
|
97
|
-
// re-scaffold is a no-op on it.
|
|
98
64
|
const PROJECT_FILE = 'project.aon'
|
|
99
65
|
const PROJECT_STUB = `# Project overlay — YOURS. The scaffold creates this file once and never
|
|
100
66
|
# overwrites it, unlike every other file it writes.
|
|
@@ -127,17 +93,6 @@ const GUIDE_FILE = 'guide.aon'
|
|
|
127
93
|
const GUIDE_REL = ['model', 'guide', GUIDE_FILE]
|
|
128
94
|
|
|
129
95
|
|
|
130
|
-
// Rename a user-owned overlay from its pre-2026-08 `.aontu` name to `.aon`.
|
|
131
|
-
//
|
|
132
|
-
// Both overlays are read-if-present and written-if-absent, which is exactly
|
|
133
|
-
// the shape that turns an extension rename into DATA LOSS rather than a
|
|
134
|
-
// rename: look for `guide.aon`, find nothing, write a fresh template over the
|
|
135
|
-
// top, and the user's entity renames, hides and overrides are still sitting
|
|
136
|
-
// in `guide.aontu` being ignored. 660 generated repos carry one.
|
|
137
|
-
//
|
|
138
|
-
// So the legacy file is moved to the new name BEFORE anything reads or writes
|
|
139
|
-
// it. Contents are untouched; only the name changes. Idempotent — once the
|
|
140
|
-
// `.aon` exists this does nothing, so a re-scaffold stays a no-op.
|
|
141
96
|
function migrateOverlay(fs: any, dir: string, name: string): void {
|
|
142
97
|
const next = Path.join(dir, name + '.aon')
|
|
143
98
|
const prev = Path.join(dir, name + '.aontu')
|
|
@@ -145,15 +100,6 @@ function migrateOverlay(fs: any, dir: string, name: string): void {
|
|
|
145
100
|
return
|
|
146
101
|
}
|
|
147
102
|
try {
|
|
148
|
-
// RENAME THE FILE *AND* ITS INCLUDES. An overlay written before the
|
|
149
|
-
// rename includes the toolchain schemas by their old names —
|
|
150
|
-
// `@"@voxgig/apidef/model/guide.aontu"` — and apidef 8 no longer ships
|
|
151
|
-
// that file, so a migration that moved the file but kept its contents
|
|
152
|
-
// verbatim produced a project that could not resolve its own guide.
|
|
153
|
-
// mergeGuide cannot repair this either: it keeps the user's lines and
|
|
154
|
-
// only ADDS missing template includes, so the dead one would survive
|
|
155
|
-
// beside the new one. Only `@`-include extensions are touched; nothing
|
|
156
|
-
// else in the user's file is rewritten.
|
|
157
103
|
const src = String(fs.readFileSync(prev))
|
|
158
104
|
.replace(/(@['"][^'"]+)\.aontu(['"])/g, '$1.aon$2')
|
|
159
105
|
fs.writeFileSync(next, src)
|
|
@@ -166,17 +112,6 @@ function migrateOverlay(fs: any, dir: string, name: string): void {
|
|
|
166
112
|
}
|
|
167
113
|
|
|
168
114
|
|
|
169
|
-
// Merge the guide template into an existing guide overlay.
|
|
170
|
-
//
|
|
171
|
-
// A guide is the template's `@`-includes plus whatever the user added. The
|
|
172
|
-
// includes are the only part the template OWNS, so the merge is: keep the
|
|
173
|
-
// user's file verbatim, and restore any include it is missing. When nothing
|
|
174
|
-
// is missing — the normal case — the file is returned byte-identical, so a
|
|
175
|
-
// re-scaffold is a no-op on it.
|
|
176
|
-
//
|
|
177
|
-
// Missing includes are restored at the TOP, not appended: `base-guide.aon`
|
|
178
|
-
// carries the heuristic classification that the user's overrides unify over,
|
|
179
|
-
// and the overlay reads correctly only when the includes precede it.
|
|
180
115
|
function mergeGuide(existing: string | null, template: string): string {
|
|
181
116
|
if (null == existing) {
|
|
182
117
|
return template
|
|
@@ -184,18 +119,6 @@ function mergeGuide(existing: string | null, template: string): string {
|
|
|
184
119
|
|
|
185
120
|
const isInclude = (line: string) => line.trim().startsWith('@')
|
|
186
121
|
|
|
187
|
-
// AN INCLUDE IS THE FILE IT NAMES, whichever way the `./` falls.
|
|
188
|
-
//
|
|
189
|
-
// The template gained a `./` when aontu 0.65 made a bare single-segment
|
|
190
|
-
// include name a PACKAGE (ADR-039). Every guide written before that says
|
|
191
|
-
// `@"base-guide.aon"`, and `guide.aon` is project-owned: the scaffold
|
|
192
|
-
// writes it once and never again, so those files stay as they are until
|
|
193
|
-
// something migrates them.
|
|
194
|
-
//
|
|
195
|
-
// Comparing the raw lines read the old spelling as a DIFFERENT include, so
|
|
196
|
-
// a re-scaffold restored one the file already had — leaving the guide
|
|
197
|
-
// including `base-guide.aon` twice, under two spellings, which is the one
|
|
198
|
-
// thing this merge exists to avoid.
|
|
199
122
|
const key = (line: string) => line.trim().replace(/^@"\.\//, '@"')
|
|
200
123
|
|
|
201
124
|
const have = new Set(existing.split('\n').map(key))
|
|
@@ -212,26 +135,10 @@ function mergeGuide(existing: string | null, template: string): string {
|
|
|
212
135
|
}
|
|
213
136
|
|
|
214
137
|
|
|
215
|
-
// The OpenAPI filename is inherited from the upstream API slug, and upstream
|
|
216
|
-
// slugs are not constrained: the freepublicapis corpus contains apostrophes
|
|
217
|
-
// (catherine-shulman's-quotes), accents (dólar-y-monedas, kölner-adressen),
|
|
218
|
-
// and '!' / '>' / '_'. That name is copied into .sdk/def/ AND written verbatim
|
|
219
|
-
// into a single-quoted aontu string in sdk.aon:
|
|
220
|
-
//
|
|
221
|
-
// def: 'catherine-shulman's-quotes_0.1.0.json'
|
|
222
|
-
// ^ terminates the string -> AontuError, no SDK
|
|
223
|
-
//
|
|
224
|
-
// Slugs are [a-z0-9-]; a filename additionally needs '.' and '_' for the
|
|
225
|
-
// version segment and extension, so those are kept — which also means every
|
|
226
|
-
// already-conforming name (including cedar's dotted gitlab-v4-swagger-2.0.yaml)
|
|
227
|
-
// is untouched and no repo churns. Everything else is folded to '-'.
|
|
228
138
|
function sanitizeDefName(filename: string): string {
|
|
229
139
|
const clean = filename
|
|
230
|
-
.normalize('NFKD').replace(/[\u0300-\u036f]/g, '')
|
|
140
|
+
.normalize('NFKD').replace(/[\u0300-\u036f]/g, '')
|
|
231
141
|
.toLowerCase()
|
|
232
|
-
// Quotes are ELIDED, not folded to '-', so the filename agrees with the
|
|
233
|
-
// repo name apidef's sanitizeSlug derives from the same slug:
|
|
234
|
-
// catherine-shulman's-quotes -> catherine-shulmans-quotes(-sdk).
|
|
235
142
|
.replace(/['’"]/g, '')
|
|
236
143
|
.replace(/[^a-z0-9._-]+/g, '-')
|
|
237
144
|
.replace(/-+/g, '-')
|
|
@@ -244,17 +151,13 @@ function sanitizeDefName(filename: string): string {
|
|
|
244
151
|
}
|
|
245
152
|
|
|
246
153
|
|
|
247
|
-
// TODO: rename to RootSdk
|
|
248
154
|
const CreateRoot = cmp(function CreateRoot(props: any) {
|
|
249
155
|
const { ctx$, ctx$: { folder }, spec, model } = props
|
|
250
156
|
const fs = ctx$.fs()
|
|
251
157
|
|
|
252
|
-
// TODO: move to @voxgig/util as duplicated
|
|
253
158
|
model.const = { name: model.name }
|
|
254
159
|
names(model.const, model.name)
|
|
255
160
|
model.const.year = new Date().getFullYear()
|
|
256
|
-
// Scaffold is MIT-licensed (matches the emitted LICENSE and tm/LICENSE);
|
|
257
|
-
// set directly rather than via names() so the value stays 'MIT', not 'Mit'.
|
|
258
161
|
model.const.License = 'MIT'
|
|
259
162
|
|
|
260
163
|
ctx$.model = model
|
|
@@ -263,11 +166,7 @@ const CreateRoot = cmp(function CreateRoot(props: any) {
|
|
|
263
166
|
const from =
|
|
264
167
|
Path.resolve(Path.join(__dirname, '..', '..', '..', 'project', 'standard'))
|
|
265
168
|
|
|
266
|
-
// console.log('FROM', from)
|
|
267
169
|
|
|
268
|
-
// Copy `exclude` matches the SOURCE-RELATIVE path exactly, so this names
|
|
269
|
-
// the one guide under the scaffold and nothing else. It is re-emitted,
|
|
270
|
-
// merged, in the model folder below.
|
|
271
170
|
const guideExclude = [spec.sdk_folder, ...GUIDE_REL].join('/')
|
|
272
171
|
|
|
273
172
|
Copy({
|
|
@@ -296,7 +195,6 @@ const CreateRoot = cmp(function CreateRoot(props: any) {
|
|
|
296
195
|
})
|
|
297
196
|
|
|
298
197
|
Folder({ name: 'def' }, () => {
|
|
299
|
-
// TODO: file existence check should be jostraca util
|
|
300
198
|
if (fs.existsSync(origdef)) {
|
|
301
199
|
Copy({ from: origdef, to: projdef })
|
|
302
200
|
}
|