Skip to content

Commit 86161a1

Browse files
alan-agius4filipesilva
authored andcommitted
fix(@angular-devkit/core): handle complex smart defaults in schemas
(cherry picked from commit 9f85bc5)
1 parent bf1122b commit 86161a1

File tree

3 files changed

+42
-23
lines changed

3 files changed

+42
-23
lines changed

packages/angular_devkit/core/src/experimental/jobs/simple-scheduler_spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ describe('SimpleScheduler', () => {
102102
// is released, otherwise this breaks because bazel downgrade to ES5 which does not support
103103
// extending Error.
104104
// expect(e instanceof JobInboundMessageSchemaValidationError).toBe(true);
105-
expect(e.message).toMatch(/"\[0\]".*number/);
105+
expect(e.message).toMatch(/"\/0" must be number/);
106106
}
107107
});
108108

packages/angular_devkit/core/src/json/schema/registry.ts

+33-13
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import Ajv, { ValidateFunction } from 'ajv';
9+
import Ajv, { SchemaObjCxt, ValidateFunction } from 'ajv';
1010
import ajvAddFormats from 'ajv-formats';
1111
import * as http from 'http';
1212
import * as https from 'https';
@@ -305,6 +305,8 @@ export class CoreSchemaRegistry implements SchemaRegistry {
305305
try {
306306
this._currentCompilationSchemaInfo = schemaInfo;
307307
validator = this._ajv.compile(schema);
308+
} catch {
309+
validator = await this._ajv.compileAsync(schema);
308310
} finally {
309311
this._currentCompilationSchemaInfo = undefined;
310312
}
@@ -406,10 +408,7 @@ export class CoreSchemaRegistry implements SchemaRegistry {
406408
}
407409

408410
// We cheat, heavily.
409-
const pathArray = it.dataPathArr
410-
.slice(1, it.dataLevel + 1)
411-
.map((p) => (typeof p === 'number' ? p : p.str.slice(1, -1)));
412-
411+
const pathArray = this.normalizeDataPathArr(it);
413412
compilationSchemInfo.smartDefaultRecord.set(JSON.stringify(pathArray), schema);
414413

415414
return () => true;
@@ -449,12 +448,7 @@ export class CoreSchemaRegistry implements SchemaRegistry {
449448
return () => true;
450449
}
451450

452-
const path =
453-
'/' +
454-
it.dataPathArr
455-
.slice(1, it.dataLevel + 1)
456-
.map((p) => (typeof p === 'number' ? p : p.str.slice(1, -1)))
457-
.join('/');
451+
const path = '/' + this.normalizeDataPathArr(it).join('/');
458452

459453
let type: string | undefined;
460454
let items: Array<string | { label: string; value: string | number | boolean }> | undefined;
@@ -593,11 +587,31 @@ export class CoreSchemaRegistry implements SchemaRegistry {
593587
data: any,
594588
fragments: string[],
595589
value: unknown,
596-
parent: Record<string, unknown> | null = null,
590+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
591+
parent: any = null,
597592
parentProperty?: string,
598593
force?: boolean,
599594
): void {
600-
for (const fragment of fragments) {
595+
for (let index = 0; index < fragments.length; index++) {
596+
const fragment = fragments[index];
597+
if (/^i\d+$/.test(fragment)) {
598+
if (!Array.isArray(data)) {
599+
return;
600+
}
601+
602+
for (let dataIndex = 0; dataIndex < data.length; dataIndex++) {
603+
CoreSchemaRegistry._set(
604+
data[dataIndex],
605+
fragments.slice(index + 1),
606+
value,
607+
data,
608+
`${dataIndex}`,
609+
);
610+
}
611+
612+
return;
613+
}
614+
601615
if (!data && parent !== null && parentProperty) {
602616
data = parent[parentProperty] = {};
603617
}
@@ -665,4 +679,10 @@ export class CoreSchemaRegistry implements SchemaRegistry {
665679
);
666680
}
667681
}
682+
683+
private normalizeDataPathArr(it: SchemaObjCxt): (number | string)[] {
684+
return it.dataPathArr
685+
.slice(1, it.dataLevel + 1)
686+
.map((p) => (typeof p === 'number' ? p : p.str.replace(/\"/g, '')));
687+
}
668688
}

packages/angular_devkit/core/src/json/schema/registry_spec.ts

+8-9
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ describe('CoreSchemaRegistry', () => {
3030
},
3131
},
3232
tslint: {
33-
$ref: 'https://json.schemastore.org/tslint#',
33+
$ref: 'https://json.schemastore.org/npm-link-up#',
3434
},
3535
},
3636
})
@@ -130,7 +130,7 @@ describe('CoreSchemaRegistry', () => {
130130
map((result) => {
131131
expect(result.success).toBe(false);
132132
expect(result.errors && result.errors[0].message).toContain(
133-
'should NOT have additional properties',
133+
'must NOT have additional properties',
134134
);
135135
}),
136136
)
@@ -180,10 +180,10 @@ describe('CoreSchemaRegistry', () => {
180180
mergeMap((validator) => validator(data)),
181181
map((result) => {
182182
expect(result.success).toBe(false);
183-
expect(result.errors && result.errors[0].message).toContain(
184-
'should NOT have additional properties',
183+
expect(result.errors?.[0].message).toContain(
184+
'must NOT have additional properties',
185185
);
186-
expect(result.errors && result.errors[0].keyword).toBe('additionalProperties');
186+
expect(result.errors?.[0].keyword).toBe('additionalProperties');
187187
}),
188188
)
189189
.toPromise()
@@ -249,7 +249,7 @@ describe('CoreSchemaRegistry', () => {
249249
.then(done, done.fail);
250250
});
251251

252-
it('shows dataPath and message on error', (done) => {
252+
it('shows dataPath and message on error', async () => {
253253
const registry = new CoreSchemaRegistry();
254254
const data = { hotdot: 'hotdog', banana: 'banana' };
255255
const format: SchemaFormat = {
@@ -262,7 +262,7 @@ describe('CoreSchemaRegistry', () => {
262262

263263
registry.addFormat(format);
264264

265-
registry
265+
await registry
266266
.compile({
267267
properties: {
268268
hotdot: { type: 'string', format: 'is-hotdog' },
@@ -275,12 +275,11 @@ describe('CoreSchemaRegistry', () => {
275275
expect(result.success).toBe(false);
276276
expect(result.errors && result.errors[0]).toBeTruthy();
277277
expect(result.errors && result.errors[0].keyword).toBe('format');
278-
expect(result.errors && result.errors[0].instancePath).toBe('.banana');
278+
expect(result.errors && result.errors[0].instancePath).toBe('/banana');
279279
expect(result.errors && (result.errors[0].params as any).format).toBe('is-hotdog');
280280
}),
281281
)
282282
.toPromise()
283-
.then(done, done.fail);
284283
});
285284

286285
it('supports smart defaults', (done) => {

0 commit comments

Comments
 (0)