@snowtop/ent 0.1.0-alpha31 → 0.1.0-alpha40
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/action/action.d.ts +2 -2
- package/action/orchestrator.js +51 -19
- package/package.json +1 -1
- package/schema/schema.d.ts +4 -4
- package/testutils/builder.d.ts +4 -1
- package/testutils/builder.js +9 -0
- package/tsc/transform_action.d.ts +2 -0
- package/tsc/transform_action.js +26 -16
- package/tsc/transform_schema.js +34 -9
package/action/action.d.ts
CHANGED
|
@@ -49,11 +49,11 @@ export interface Action<TEnt extends Ent<TViewer>, TBuilder extends Builder<TEnt
|
|
|
49
49
|
changeset(): Promise<Changeset>;
|
|
50
50
|
builder: TBuilder;
|
|
51
51
|
getPrivacyPolicy(): PrivacyPolicy<TEnt>;
|
|
52
|
-
getTriggers?(): Trigger<TEnt, TBuilder, TViewer, TInput, TExistingEnt>[];
|
|
52
|
+
getTriggers?(): (Trigger<TEnt, TBuilder, TViewer, TInput, TExistingEnt> | Trigger<TEnt, TBuilder, TViewer, TInput, TExistingEnt>[])[];
|
|
53
53
|
getObservers?(): Observer<TEnt, TBuilder, TViewer, TInput, TExistingEnt>[];
|
|
54
54
|
getValidators?(): Validator<TEnt, TBuilder, TViewer, TInput, TExistingEnt>[];
|
|
55
55
|
getInput(): TInput;
|
|
56
|
-
transformWrite?: (stmt: UpdateOperation<TEnt>) => Promise<TransformedUpdateOperation<TEnt>> | TransformedUpdateOperation<TEnt> | null;
|
|
56
|
+
transformWrite?: (stmt: UpdateOperation<TEnt, TViewer>) => Promise<TransformedUpdateOperation<TEnt>> | TransformedUpdateOperation<TEnt> | null;
|
|
57
57
|
valid(): Promise<boolean>;
|
|
58
58
|
validX(): Promise<void>;
|
|
59
59
|
viewerForEntLoad?(data: Data): TViewer | Promise<TViewer>;
|
package/action/orchestrator.js
CHANGED
|
@@ -333,22 +333,46 @@ class Orchestrator {
|
|
|
333
333
|
]);
|
|
334
334
|
}
|
|
335
335
|
async triggers(action, builder, triggers) {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
if (Array.isArray(
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
}
|
|
336
|
+
let groups = [];
|
|
337
|
+
let lastArray = 0;
|
|
338
|
+
let prevWasArray = false;
|
|
339
|
+
for (let i = 0; i < triggers.length; i++) {
|
|
340
|
+
let t = triggers[i];
|
|
341
|
+
if (Array.isArray(t)) {
|
|
342
|
+
if (!prevWasArray) {
|
|
343
|
+
// @ts-ignore
|
|
344
|
+
groups.push(triggers.slice(lastArray, i));
|
|
346
345
|
}
|
|
346
|
+
groups.push(t);
|
|
347
|
+
prevWasArray = true;
|
|
348
|
+
lastArray++;
|
|
347
349
|
}
|
|
348
|
-
else
|
|
349
|
-
|
|
350
|
+
else {
|
|
351
|
+
if (i === triggers.length - 1) {
|
|
352
|
+
// @ts-ignore
|
|
353
|
+
groups.push(triggers.slice(lastArray, i + 1));
|
|
354
|
+
}
|
|
355
|
+
prevWasArray = false;
|
|
350
356
|
}
|
|
351
|
-
}
|
|
357
|
+
}
|
|
358
|
+
for (const triggers of groups) {
|
|
359
|
+
await Promise.all(triggers.map(async (trigger) => {
|
|
360
|
+
let ret = await trigger.changeset(builder, action.getInput());
|
|
361
|
+
if (Array.isArray(ret)) {
|
|
362
|
+
ret = await Promise.all(ret);
|
|
363
|
+
}
|
|
364
|
+
if (Array.isArray(ret)) {
|
|
365
|
+
for (const v of ret) {
|
|
366
|
+
if (typeof v === "object") {
|
|
367
|
+
this.changesets.push(v);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
else if (ret) {
|
|
372
|
+
this.changesets.push(ret);
|
|
373
|
+
}
|
|
374
|
+
}));
|
|
375
|
+
}
|
|
352
376
|
}
|
|
353
377
|
async validators(validators, action, builder) {
|
|
354
378
|
let promises = [];
|
|
@@ -379,23 +403,29 @@ class Orchestrator {
|
|
|
379
403
|
// if disable transformations set, don't do schema transform and just do the right thing
|
|
380
404
|
// else apply schema tranformation if it exists
|
|
381
405
|
let transformed = null;
|
|
406
|
+
const sqlOp = this.getSQLStatementOperation();
|
|
382
407
|
if (action?.transformWrite) {
|
|
383
408
|
transformed = await action.transformWrite({
|
|
384
|
-
|
|
385
|
-
|
|
409
|
+
builder,
|
|
410
|
+
input,
|
|
411
|
+
op: sqlOp,
|
|
386
412
|
data: editedFields,
|
|
387
|
-
existingEnt: this.existingEnt,
|
|
388
413
|
});
|
|
389
414
|
}
|
|
390
415
|
else if (!this.disableTransformations) {
|
|
391
416
|
transformed = (0, schema_1.getTransformedUpdateOp)(this.options.schema, {
|
|
392
|
-
|
|
393
|
-
|
|
417
|
+
builder,
|
|
418
|
+
input,
|
|
419
|
+
op: sqlOp,
|
|
394
420
|
data: editedFields,
|
|
395
|
-
existingEnt: this.existingEnt,
|
|
396
421
|
});
|
|
397
422
|
}
|
|
398
423
|
if (transformed) {
|
|
424
|
+
if (sqlOp === schema_1.SQLStatementOperation.Insert && sqlOp !== transformed.op) {
|
|
425
|
+
if (!transformed.existingEnt) {
|
|
426
|
+
throw new Error(`cannot transform an insert operation without providing an existing ent`);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
399
429
|
if (transformed.data) {
|
|
400
430
|
updateInput = true;
|
|
401
431
|
for (const k in transformed.data) {
|
|
@@ -418,6 +448,8 @@ class Orchestrator {
|
|
|
418
448
|
if (transformed.existingEnt) {
|
|
419
449
|
// @ts-ignore
|
|
420
450
|
this.existingEnt = transformed.existingEnt;
|
|
451
|
+
// modify existing ent in builder. it's readonly in generated ents but doesn't apply here
|
|
452
|
+
builder.existingEnt = transformed.existingEnt;
|
|
421
453
|
}
|
|
422
454
|
}
|
|
423
455
|
// transforming before doing default fields so that we don't create a new id
|
package/package.json
CHANGED
package/schema/schema.d.ts
CHANGED
|
@@ -82,10 +82,10 @@ export declare enum SQLStatementOperation {
|
|
|
82
82
|
Update = "update",
|
|
83
83
|
Delete = "delete"
|
|
84
84
|
}
|
|
85
|
-
export interface UpdateOperation<
|
|
85
|
+
export interface UpdateOperation<TEnt extends Ent<TViewer>, TViewer extends Viewer = Viewer> {
|
|
86
86
|
op: SQLStatementOperation;
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
builder: Builder<TEnt, TViewer>;
|
|
88
|
+
input: Data;
|
|
89
89
|
data?: Map<string, any>;
|
|
90
90
|
}
|
|
91
91
|
export interface TransformedUpdateOperation<T extends Ent> {
|
|
@@ -204,7 +204,7 @@ interface objectLoaderOptions {
|
|
|
204
204
|
instanceKey?: string;
|
|
205
205
|
}
|
|
206
206
|
export declare function getObjectLoaderProperties(value: SchemaInputType, tableName: string): objectLoaderOptions | undefined;
|
|
207
|
-
export declare function getTransformedUpdateOp<
|
|
207
|
+
export declare function getTransformedUpdateOp<TEnt extends Ent<TViewer>, TViewer extends Viewer>(value: SchemaInputType, stmt: UpdateOperation<TEnt, TViewer>): TransformedUpdateOperation<TEnt> | null;
|
|
208
208
|
export declare enum ActionOperation {
|
|
209
209
|
Create = 1,
|
|
210
210
|
Edit = 2,
|
package/testutils/builder.d.ts
CHANGED
|
@@ -80,9 +80,12 @@ export declare class SimpleBuilder<T extends Ent, TExistingEnt extends TMaybleNu
|
|
|
80
80
|
orchestrator: Orchestrator<T, Data, Viewer>;
|
|
81
81
|
fields: Map<string, any>;
|
|
82
82
|
nodeType: string;
|
|
83
|
+
m: Map<string, any>;
|
|
83
84
|
constructor(viewer: Viewer, schema: BuilderSchema<T>, fields: Map<string, any>, operation: WriteOperation, existingEnt: TExistingEnt, action?: Action<T, SimpleBuilder<T>, Viewer, Data> | undefined);
|
|
84
85
|
getInput(): Data;
|
|
85
86
|
updateInput(input: Data): void;
|
|
87
|
+
storeData(k: string, v: any): void;
|
|
88
|
+
getStoredData(k: string): any;
|
|
86
89
|
build(): Promise<Changeset>;
|
|
87
90
|
editedEnt(): Promise<T | null>;
|
|
88
91
|
editedEntX(): Promise<T>;
|
|
@@ -100,7 +103,7 @@ export declare class SimpleAction<T extends Ent, TExistingEnt extends TMaybleNul
|
|
|
100
103
|
builder: SimpleBuilder<T, TExistingEnt>;
|
|
101
104
|
viewerForEntLoad: viewerEntLoadFunc | undefined;
|
|
102
105
|
constructor(viewer: Viewer, schema: BuilderSchema<T>, fields: Map<string, any>, operation: WriteOperation | undefined, existingEnt: TExistingEnt);
|
|
103
|
-
getTriggers(): Trigger<T, SimpleBuilder<T>>[];
|
|
106
|
+
getTriggers(): (Trigger<T, SimpleBuilder<T>> | Array<Trigger<T, SimpleBuilder<T>>>)[];
|
|
104
107
|
getValidators(): Validator<T, SimpleBuilder<T>>[];
|
|
105
108
|
getObservers(): Observer<T, SimpleBuilder<T>>[];
|
|
106
109
|
getPrivacyPolicy(): PrivacyPolicy<Ent<Viewer<Ent<any> | null, ID | null>>, Viewer<Ent<any> | null, ID | null>>;
|
package/testutils/builder.js
CHANGED
|
@@ -150,6 +150,7 @@ class SimpleBuilder {
|
|
|
150
150
|
this.schema = schema;
|
|
151
151
|
this.operation = operation;
|
|
152
152
|
this.existingEnt = existingEnt;
|
|
153
|
+
this.m = new Map();
|
|
153
154
|
// create dynamic placeholder
|
|
154
155
|
// TODO: do we need to use this as the node when there's an existingEnt
|
|
155
156
|
// same for generated builders.
|
|
@@ -230,6 +231,14 @@ class SimpleBuilder {
|
|
|
230
231
|
}
|
|
231
232
|
}
|
|
232
233
|
}
|
|
234
|
+
// store data in Builder that can be retrieved by another validator, trigger, observer later in the action
|
|
235
|
+
storeData(k, v) {
|
|
236
|
+
this.m.set(k, v);
|
|
237
|
+
}
|
|
238
|
+
// retrieve data stored in this Builder with key
|
|
239
|
+
getStoredData(k) {
|
|
240
|
+
return this.m.get(k);
|
|
241
|
+
}
|
|
233
242
|
build() {
|
|
234
243
|
return this.orchestrator.build();
|
|
235
244
|
}
|
|
@@ -11,10 +11,12 @@ export declare class TransformAction implements TransformFile {
|
|
|
11
11
|
rawString?: undefined;
|
|
12
12
|
traversed?: undefined;
|
|
13
13
|
imports?: undefined;
|
|
14
|
+
removeImports?: undefined;
|
|
14
15
|
} | {
|
|
15
16
|
rawString: string;
|
|
16
17
|
traversed: boolean;
|
|
17
18
|
imports: Map<string, string[]>;
|
|
19
|
+
removeImports: string[];
|
|
18
20
|
node?: undefined;
|
|
19
21
|
} | undefined;
|
|
20
22
|
}
|
package/tsc/transform_action.js
CHANGED
|
@@ -25,11 +25,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
25
25
|
exports.TransformAction = void 0;
|
|
26
26
|
const typescript_1 = __importDefault(require("typescript"));
|
|
27
27
|
const ast_1 = require("../tsc/ast");
|
|
28
|
-
const action_1 = require("../action");
|
|
29
28
|
const viewer_1 = require("../core/viewer");
|
|
30
29
|
const path = __importStar(require("path"));
|
|
31
30
|
const snake_case_1 = require("snake-case");
|
|
32
|
-
|
|
31
|
+
// returns input and importPath
|
|
32
|
+
function getBaseFileInfo(file, classInfo, sourceFile) {
|
|
33
33
|
// @ts-ignore
|
|
34
34
|
const importStatements = sourceFile.statements.filter((stmt) => typescript_1.default.isImportDeclaration(stmt));
|
|
35
35
|
for (const imp of importStatements) {
|
|
@@ -49,13 +49,19 @@ function findInput(file, classInfo, sourceFile) {
|
|
|
49
49
|
.filter((imp) => imp.trim() && imp.endsWith("Input"))
|
|
50
50
|
.map((v) => v.trim());
|
|
51
51
|
if (inputs.length === 1) {
|
|
52
|
-
return
|
|
52
|
+
return {
|
|
53
|
+
input: inputs[0],
|
|
54
|
+
importPath: impInfo.importPath,
|
|
55
|
+
};
|
|
53
56
|
}
|
|
54
57
|
if (inputs.length && classInfo.name.endsWith("Action")) {
|
|
55
58
|
const prefix = classInfo.name.slice(0, classInfo.name.length - 6);
|
|
56
59
|
inputs = inputs.filter((imp) => imp.slice(0, imp.length - 5) === prefix);
|
|
57
60
|
if (inputs.length === 1) {
|
|
58
|
-
return
|
|
61
|
+
return {
|
|
62
|
+
input: inputs[0],
|
|
63
|
+
importPath: impInfo.importPath,
|
|
64
|
+
};
|
|
59
65
|
}
|
|
60
66
|
}
|
|
61
67
|
}
|
|
@@ -66,17 +72,20 @@ let m = {
|
|
|
66
72
|
triggers: {
|
|
67
73
|
m: "getTriggers",
|
|
68
74
|
i: "Trigger",
|
|
75
|
+
suffix: "Triggers",
|
|
69
76
|
},
|
|
70
77
|
observers: {
|
|
71
78
|
m: "getObservers",
|
|
72
79
|
i: "Observer",
|
|
80
|
+
suffix: "Observers",
|
|
73
81
|
},
|
|
74
82
|
validators: {
|
|
75
83
|
m: "getValidators",
|
|
76
84
|
i: "Validator",
|
|
85
|
+
suffix: "Validators",
|
|
77
86
|
},
|
|
78
87
|
};
|
|
79
|
-
function getConversionInfo(mm) {
|
|
88
|
+
function getConversionInfo(mm, actionName) {
|
|
80
89
|
if (mm.kind !== typescript_1.default.SyntaxKind.PropertyDeclaration) {
|
|
81
90
|
return null;
|
|
82
91
|
}
|
|
@@ -89,6 +98,8 @@ function getConversionInfo(mm) {
|
|
|
89
98
|
text,
|
|
90
99
|
method: v.m,
|
|
91
100
|
interface: v.i,
|
|
101
|
+
// CreateFooActionTriggers etc
|
|
102
|
+
methodType: actionName + v.suffix,
|
|
92
103
|
};
|
|
93
104
|
}
|
|
94
105
|
class TransformAction {
|
|
@@ -109,21 +120,19 @@ class TransformAction {
|
|
|
109
120
|
// require action
|
|
110
121
|
const p = require(path.join(process.cwd(), "./" + file.slice(0, -3)));
|
|
111
122
|
const action = new p.default(new viewer_1.LoggedOutViewer(), {});
|
|
123
|
+
const actionName = action.constructor.name;
|
|
112
124
|
const builder = action.builder.constructor.name;
|
|
113
125
|
const nodeName = action.builder.ent.name;
|
|
114
|
-
const existingEnt = action.builder.operation === action_1.WriteOperation.Insert
|
|
115
|
-
? `${nodeName} | null`
|
|
116
|
-
: nodeName;
|
|
117
126
|
const viewer = this.customInfo.viewerInfo.name;
|
|
118
|
-
const
|
|
119
|
-
if (!
|
|
127
|
+
const baseInfo = getBaseFileInfo(file, classInfo, sourceFile);
|
|
128
|
+
if (!baseInfo) {
|
|
120
129
|
return;
|
|
121
130
|
}
|
|
122
131
|
let klassContents = "";
|
|
123
132
|
let traversed = false;
|
|
124
133
|
let newImports = [];
|
|
125
134
|
for (const mm of node.members) {
|
|
126
|
-
const conv = getConversionInfo(mm);
|
|
135
|
+
const conv = getConversionInfo(mm, actionName);
|
|
127
136
|
if (conv !== null) {
|
|
128
137
|
const property = mm;
|
|
129
138
|
// if invalid, bounce
|
|
@@ -132,10 +141,10 @@ class TransformAction {
|
|
|
132
141
|
}
|
|
133
142
|
traversed = true;
|
|
134
143
|
const pp = property.initializer.getFullText(sourceFile).trim();
|
|
135
|
-
const code = `${conv.method}(): ${conv.
|
|
144
|
+
const code = `${conv.method}(): ${conv.methodType} {
|
|
136
145
|
return ${pp}
|
|
137
146
|
}`;
|
|
138
|
-
newImports.push(conv.
|
|
147
|
+
newImports.push(conv.methodType);
|
|
139
148
|
klassContents += (0, ast_1.getPreText)(contents, mm, sourceFile) + code;
|
|
140
149
|
}
|
|
141
150
|
else {
|
|
@@ -149,10 +158,9 @@ class TransformAction {
|
|
|
149
158
|
[viewer],
|
|
150
159
|
],
|
|
151
160
|
[
|
|
152
|
-
(0, ast_1.transformRelative)(file,
|
|
153
|
-
|
|
161
|
+
(0, ast_1.transformRelative)(file, baseInfo.importPath, this.customInfo.relativeImports),
|
|
162
|
+
newImports,
|
|
154
163
|
],
|
|
155
|
-
["@snowtop/ent/action", newImports],
|
|
156
164
|
[
|
|
157
165
|
(0, ast_1.transformRelative)(file, builderPath, this.customInfo.relativeImports),
|
|
158
166
|
[builder],
|
|
@@ -163,6 +171,8 @@ class TransformAction {
|
|
|
163
171
|
rawString: classInfo.wrapClassContents(klassContents),
|
|
164
172
|
traversed,
|
|
165
173
|
imports,
|
|
174
|
+
removeImports: ["Trigger", "Observer", "Validator"],
|
|
175
|
+
// not removing FooBuilder incase it's still somehow used in type of inline builders
|
|
166
176
|
};
|
|
167
177
|
}
|
|
168
178
|
}
|
package/tsc/transform_schema.js
CHANGED
|
@@ -91,7 +91,7 @@ function getTransformClassInfo(fileContents, sourceFile, node, transformSchema)
|
|
|
91
91
|
}
|
|
92
92
|
// intentionally doesn't parse decorators since we don't need it
|
|
93
93
|
function getClassElementInfo(fileContents, member, sourceFile) {
|
|
94
|
-
if (isFieldElement(member, sourceFile)) {
|
|
94
|
+
if (isFieldElement(fileContents, member, sourceFile)) {
|
|
95
95
|
return getFieldElementInfo(fileContents, member, sourceFile);
|
|
96
96
|
}
|
|
97
97
|
if (member.kind === typescript_1.default.SyntaxKind.Constructor) {
|
|
@@ -201,7 +201,7 @@ function getConstructorElementInfo(fileContents, member, sourceFile) {
|
|
|
201
201
|
comment: "",
|
|
202
202
|
};
|
|
203
203
|
}
|
|
204
|
-
function isFieldElement(member, sourceFile) {
|
|
204
|
+
function isFieldElement(fileContents, member, sourceFile) {
|
|
205
205
|
if (member.kind !== typescript_1.default.SyntaxKind.PropertyDeclaration) {
|
|
206
206
|
return false;
|
|
207
207
|
}
|
|
@@ -215,16 +215,31 @@ function isFieldElement(member, sourceFile) {
|
|
|
215
215
|
return false;
|
|
216
216
|
}
|
|
217
217
|
if (property.initializer?.kind !== typescript_1.default.SyntaxKind.ArrayLiteralExpression) {
|
|
218
|
-
|
|
218
|
+
throwErr(fileContents, member, "invalid array type");
|
|
219
219
|
return false;
|
|
220
220
|
}
|
|
221
221
|
return true;
|
|
222
222
|
}
|
|
223
|
+
// if there's an error transforming any of the schemas, we should stop...
|
|
224
|
+
function throwErr(fileContents, node, error) {
|
|
225
|
+
console.error(error);
|
|
226
|
+
throw new Error(`error transforming this field ${fileContents.substring(node.getFullStart(), node.getEnd())}`);
|
|
227
|
+
}
|
|
223
228
|
function parseFieldElement(element, sourceFile, fileContents, nested) {
|
|
224
|
-
if (element.kind !== typescript_1.default.SyntaxKind.CallExpression
|
|
225
|
-
|
|
229
|
+
if (element.kind !== typescript_1.default.SyntaxKind.CallExpression &&
|
|
230
|
+
element.kind !== typescript_1.default.SyntaxKind.PropertyAccessExpression) {
|
|
231
|
+
throwErr(fileContents, element, `skipped unknown (non-call|non-property) expression ${element.kind}`);
|
|
226
232
|
return null;
|
|
227
233
|
}
|
|
234
|
+
if (element.kind === typescript_1.default.SyntaxKind.PropertyAccessExpression) {
|
|
235
|
+
const ret = parseFieldElement(element.expression, sourceFile, fileContents, true);
|
|
236
|
+
if (ret !== null) {
|
|
237
|
+
if (!nested) {
|
|
238
|
+
ret.suffix = fileContents.substring(ret.callEx.getEnd(), element.getEnd());
|
|
239
|
+
}
|
|
240
|
+
return ret;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
228
243
|
let callEx = element;
|
|
229
244
|
if (callEx.arguments.length !== 1) {
|
|
230
245
|
// have a situation like: StringType({ name: "canonicalName" }).trim().toLowerCase(),
|
|
@@ -238,12 +253,22 @@ function parseFieldElement(element, sourceFile, fileContents, nested) {
|
|
|
238
253
|
return ret;
|
|
239
254
|
}
|
|
240
255
|
}
|
|
241
|
-
|
|
242
|
-
return null;
|
|
256
|
+
throwErr(fileContents, element, "callExpression with arguments not of length 1");
|
|
243
257
|
}
|
|
244
258
|
let arg = callEx.arguments[0];
|
|
245
259
|
if (arg.kind !== typescript_1.default.SyntaxKind.ObjectLiteralExpression) {
|
|
246
|
-
|
|
260
|
+
// this and the check above for PropertyAccessExpression are to handle things like
|
|
261
|
+
// FooType({
|
|
262
|
+
/// ...
|
|
263
|
+
// }).function(blah)
|
|
264
|
+
const ret = parseFieldElement(callEx.expression, sourceFile, fileContents, true);
|
|
265
|
+
if (ret !== null) {
|
|
266
|
+
if (!nested) {
|
|
267
|
+
ret.suffix = fileContents.substring(ret.callEx.getEnd(), callEx.getEnd());
|
|
268
|
+
}
|
|
269
|
+
return ret;
|
|
270
|
+
}
|
|
271
|
+
throwErr(fileContents, element, `not objectLiteralExpression. kind ${arg.kind}`);
|
|
247
272
|
return null;
|
|
248
273
|
}
|
|
249
274
|
let expr = arg;
|
|
@@ -263,7 +288,7 @@ function parseFieldElement(element, sourceFile, fileContents, nested) {
|
|
|
263
288
|
}
|
|
264
289
|
}
|
|
265
290
|
if (!name) {
|
|
266
|
-
|
|
291
|
+
throwErr(fileContents, element, `couldn't find name property`);
|
|
267
292
|
return null;
|
|
268
293
|
}
|
|
269
294
|
// remove quotes
|