Skip to content

Commit 2363064

Browse files
hanslMRHarrison
authored andcommitted
fix(@ngtools/json-schema): serialize object properties better. (angular#4103)
The problem was that in an object that allowed additional properties, we were not serializing the object new values properly. Fixes angular#4044.
1 parent a78fc95 commit 2363064

File tree

8 files changed

+431
-23
lines changed

8 files changed

+431
-23
lines changed

packages/@ngtools/json-schema/src/serializers/json.spec.ts

+24-22
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,28 @@ import {RootSchemaTreeNode} from '../schema-tree';
77

88

99
describe('JsonSerializer', () => {
10-
const schemaJsonFilePath = path.join(__dirname, '../../tests/schema1.json');
11-
const schemaJson = JSON.parse(fs.readFileSync(schemaJsonFilePath, 'utf-8'));
12-
const valueJsonFilePath = path.join(__dirname, '../../tests/value1.json');
13-
const valueJson = JSON.parse(fs.readFileSync(valueJsonFilePath, 'utf-8'));
14-
15-
const schemaClass = new (SchemaClassFactory(schemaJson))(valueJson);
16-
const schema: RootSchemaTreeNode = schemaClass.$$schema();
17-
18-
it('works', () => {
19-
let str = '';
20-
function writer(s: string) {
21-
str += s;
22-
}
23-
24-
const serializer = new JsonSerializer(writer);
25-
26-
serializer.start();
27-
schema.serialize(serializer);
28-
serializer.end();
29-
30-
expect(JSON.stringify(JSON.parse(str))).toEqual(JSON.stringify(valueJson));
31-
});
10+
for (const nb of [1, 2, 3]) {
11+
it(`works (${nb})`, () => {
12+
const schemaJsonFilePath = path.join(__dirname, `../../tests/serializer/schema${nb}.json`);
13+
const schemaJson = JSON.parse(fs.readFileSync(schemaJsonFilePath, 'utf-8'));
14+
const valueJsonFilePath = path.join(__dirname, `../../tests/serializer/value${nb}.json`);
15+
const valueJson = JSON.parse(fs.readFileSync(valueJsonFilePath, 'utf-8'));
16+
17+
const schemaClass = new (SchemaClassFactory(schemaJson))(valueJson);
18+
const schema: RootSchemaTreeNode = schemaClass.$$schema();
19+
20+
let str = '';
21+
function writer(s: string) {
22+
str += s;
23+
}
24+
25+
const serializer = new JsonSerializer(writer);
26+
27+
serializer.start();
28+
schema.serialize(serializer);
29+
serializer.end();
30+
31+
expect(JSON.stringify(JSON.parse(str))).toEqual(JSON.stringify(valueJson));
32+
});
33+
}
3234
});

packages/@ngtools/json-schema/src/serializers/json.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export class JsonSerializer implements Serializer {
7777
this._willOutputValue();
7878
this._writer(JSON.stringify(key));
7979
this._writer(': ');
80-
this._writer(JSON.stringify(node.value));
80+
this._writer(JSON.stringify(node.value[key]));
8181
}
8282
}
8383

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#",
3+
"id": "JsonSchema",
4+
"type": "object",
5+
"properties": {
6+
"requiredKey": {
7+
"type": "number"
8+
},
9+
"stringKeyDefault": {
10+
"type": "string",
11+
"default": "defaultValue"
12+
},
13+
"stringKey": {
14+
"type": "string"
15+
},
16+
"booleanKey": {
17+
"type": "boolean"
18+
},
19+
"numberKey": {
20+
"type": "number"
21+
},
22+
"oneOfKey1": {
23+
"oneOf": [
24+
{ "type": "string" },
25+
{ "type": "number" }
26+
]
27+
},
28+
"oneOfKey2": {
29+
"oneOf": [
30+
{ "type": "string" },
31+
{ "type": "array", "items": { "type": "string" } }
32+
]
33+
},
34+
"objectKey1": {
35+
"type": "object",
36+
"properties": {
37+
"stringKey": {
38+
"type": "string"
39+
},
40+
"objectKey": {
41+
"type": "object",
42+
"properties": {
43+
"stringKey": {
44+
"type": "string"
45+
}
46+
}
47+
}
48+
}
49+
},
50+
"objectKey2": {
51+
"type": "object",
52+
"properties": {
53+
"stringKey": {
54+
"type": "string",
55+
"default": "default objectKey2.stringKey"
56+
}
57+
},
58+
"additionalProperties": true
59+
},
60+
"arrayKey1": {
61+
"type": "array",
62+
"items": {
63+
"type": "object",
64+
"properties": {
65+
"stringKey": {
66+
"type": "string"
67+
}
68+
}
69+
}
70+
},
71+
"arrayKey2": {
72+
"type": "array",
73+
"items": {
74+
"type": "object",
75+
"properties": {
76+
"stringKey": {
77+
"type": "string"
78+
}
79+
}
80+
}
81+
}
82+
},
83+
"required": ["requiredKey"]
84+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#",
3+
"id": "JsonSchema",
4+
"type": "object",
5+
"properties": {
6+
"a": {
7+
"type": "array",
8+
"items": {
9+
"enum": [ "v1", "v2", "v3" ]
10+
}
11+
}
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
{
2+
"$comment": "Please run `npm run build-config-interface` after changing this file. Thanks!",
3+
"$schema": "http://json-schema.org/draft-04/schema#",
4+
"id": "CliConfig",
5+
"title": "Angular CLI Config Schema",
6+
"type": "object",
7+
"properties": {
8+
"project": {
9+
"description": "The global configuration of the project.",
10+
"type": "object",
11+
"properties": {
12+
"version": {
13+
"type": "string"
14+
},
15+
"name": {
16+
"type": "string"
17+
}
18+
},
19+
"additionalProperties": false
20+
},
21+
"apps": {
22+
"description": "Properties of the different applications in this project.",
23+
"type": "array",
24+
"items": {
25+
"type": "object",
26+
"properties": {
27+
"root": {
28+
"type": "string"
29+
},
30+
"outDir": {
31+
"type": "string",
32+
"default": "dist/"
33+
},
34+
"assets": {
35+
"oneOf": [
36+
{
37+
"type": "string"
38+
},
39+
{
40+
"type": "array",
41+
"items": {
42+
"type": "string"
43+
}
44+
}
45+
],
46+
"default": []
47+
},
48+
"deployUrl": {
49+
"type": "string"
50+
},
51+
"index": {
52+
"type": "string",
53+
"default": "index.html"
54+
},
55+
"main": {
56+
"type": "string"
57+
},
58+
"test": {
59+
"type": "string"
60+
},
61+
"tsconfig": {
62+
"type": "string",
63+
"default": "tsconfig.json"
64+
},
65+
"prefix": {
66+
"type": "string"
67+
},
68+
"mobile": {
69+
"type": "boolean"
70+
},
71+
"styles": {
72+
"description": "Global styles to be included in the build.",
73+
"type": "array",
74+
"items": {
75+
"oneOf": [
76+
{
77+
"type": "string"
78+
},
79+
{
80+
"type": "object",
81+
"properties": {
82+
"input": {
83+
"type": "string"
84+
}
85+
},
86+
"additionalProperties": true
87+
}
88+
]
89+
},
90+
"additionalProperties": false
91+
},
92+
"scripts": {
93+
"description": "Global scripts to be included in the build.",
94+
"type": "array",
95+
"items": {
96+
"oneOf": [
97+
{
98+
"type": "string"
99+
},
100+
{
101+
"type": "object",
102+
"properties": {
103+
"input": {
104+
"type": "string"
105+
}
106+
},
107+
"additionalProperties": true,
108+
"required": ["input"]
109+
}
110+
]
111+
},
112+
"additionalProperties": false
113+
},
114+
"environments": {
115+
"description": "Name and corresponding file for environment config.",
116+
"type": "object",
117+
"additionalProperties": true
118+
}
119+
},
120+
"additionalProperties": false
121+
},
122+
"additionalProperties": false
123+
},
124+
"addons": {
125+
"description": "Configuration reserved for installed third party addons.",
126+
"type": "array",
127+
"items": {
128+
"type": "object",
129+
"properties": {},
130+
"additionalProperties": true
131+
}
132+
},
133+
"packages": {
134+
"description": "Configuration reserved for installed third party packages.",
135+
"type": "array",
136+
"items": {
137+
"type": "object",
138+
"properties": {},
139+
"additionalProperties": true
140+
}
141+
},
142+
"e2e": {
143+
"type": "object",
144+
"properties": {
145+
"protractor": {
146+
"type": "object",
147+
"properties": {
148+
"config": {
149+
"type": "string"
150+
}
151+
},
152+
"additionalProperties": false
153+
}
154+
},
155+
"additionalProperties": false
156+
},
157+
"test": {
158+
"type": "object",
159+
"properties": {
160+
"karma": {
161+
"type": "object",
162+
"properties": {
163+
"config": {
164+
"type": "string"
165+
}
166+
},
167+
"additionalProperties": false
168+
}
169+
},
170+
"additionalProperties": false
171+
},
172+
"defaults": {
173+
"type": "object",
174+
"properties": {
175+
"styleExt": {
176+
"type": "string"
177+
},
178+
"prefixInterfaces": {
179+
"type": "boolean"
180+
},
181+
"poll": {
182+
"type": "number"
183+
},
184+
"viewEncapsulation": {
185+
"type": "string"
186+
},
187+
"changeDetection": {
188+
"type": "string"
189+
},
190+
"inline": {
191+
"type": "object",
192+
"properties": {
193+
"style": {
194+
"type": "boolean",
195+
"default": false
196+
},
197+
"template": {
198+
"type": "boolean",
199+
"default": false
200+
}
201+
}
202+
},
203+
"spec": {
204+
"type": "object",
205+
"properties": {
206+
"class": {
207+
"type": "boolean",
208+
"default": false
209+
},
210+
"component": {
211+
"type": "boolean",
212+
"default": true
213+
},
214+
"directive": {
215+
"type": "boolean",
216+
"default": true
217+
},
218+
"module": {
219+
"type": "boolean",
220+
"default": false
221+
},
222+
"pipe": {
223+
"type": "boolean",
224+
"default": true
225+
},
226+
"service": {
227+
"type": "boolean",
228+
"default": true
229+
}
230+
}
231+
}
232+
},
233+
"additionalProperties": false
234+
}
235+
},
236+
"additionalProperties": false
237+
}

0 commit comments

Comments
 (0)