-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Expand file tree
/
Copy pathgenerateOptionsSchema.ts
More file actions
142 lines (111 loc) · 5.93 KB
/
generateOptionsSchema.ts
File metadata and controls
142 lines (111 loc) · 5.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { resolve } from 'path';
import { $root, read, write } from './common';
function appendFieldsToObject(reference: any, obj: any): any {
// Make sure it is an object type
if (typeof obj === 'object') {
for (const referenceKey in reference) {
// If key exists in original object and is an object.
if (obj.hasOwnProperty(referenceKey)) {
obj[referenceKey] = appendFieldsToObject(reference[referenceKey], obj[referenceKey]);
} else {
// Does not exist in current object context
obj[referenceKey] = reference[referenceKey];
}
}
}
return obj;
}
// Combines two object's fields, giving the parentDefault a higher precedence.
function mergeDefaults(parentDefault: any, childDefault: any): any {
const newDefault: any = {};
for (const attrname in childDefault) {
newDefault[attrname] = childDefault[attrname];
}
for (const attrname in parentDefault) {
newDefault[attrname] = parentDefault[attrname];
}
return newDefault;
}
function updateDefaults(object: any, defaults: any): any {
if (defaults !== null) {
for (const key in object) {
if (object[key].hasOwnProperty('type') && object[key].type === 'object' && object[key].properties !== null) {
object[key].properties = updateDefaults(object[key].properties, mergeDefaults(defaults, object[key].default));
} else if (defaults && key in defaults) {
object[key].default = defaults[key];
}
}
}
return object;
}
function refReplace(definitions: any, ref: any): any {
// $ref is formatted as "#/definitions/ObjectName"
const referenceStringArray: string[] = ref.$ref.split('/');
// Getting "ObjectName"
const referenceName: string = referenceStringArray[referenceStringArray.length - 1];
// Make sure reference has replaced its own $ref fields and hope there are no recursive references.
definitions[referenceName] = replaceReferences(definitions, definitions[referenceName]);
// Retrieve ObjectName from definitions. (TODO: Does not retrieve inner objects)
// Need to deep copy, there are no functions in these objects.
const reference: any = JSON.parse(JSON.stringify(definitions[referenceName]));
ref = appendFieldsToObject(reference, ref);
// Remove $ref field
delete ref.$ref;
return ref;
}
function replaceReferences(definitions: any, objects: any): any {
for (const key in objects) {
if (objects[key].hasOwnProperty('$ref')) {
objects[key] = refReplace(definitions, objects[key]);
}
// Handle 'anyOf' with references
if (objects[key].hasOwnProperty('anyOf')) {
objects[key].anyOf = replaceReferences(definitions, objects[key].anyOf);
}
// Recursively replace references if this object has properties.
if (objects[key].hasOwnProperty('type') && objects[key].type === 'object' && objects[key].properties !== null) {
objects[key].properties = replaceReferences(definitions, objects[key].properties);
objects[key].properties = updateDefaults(objects[key].properties, objects[key].default);
}
// Items in array contains ref
if (objects[key].hasOwnProperty('type') && objects[key].type === "array" && objects[key].items !== null && objects[key].items.hasOwnProperty('$ref')) {
objects[key].items = refReplace(definitions, objects[key].items);
}
// Recursively replace references if the array has objects that contains ref in items.
if (objects[key].hasOwnProperty('type') && objects[key].type === "array" && objects[key].items !== null) {
objects[key].items = replaceReferences(definitions, objects[key].items);
}
}
return objects;
}
function mergeReferences(baseDefinitions: any, additionalDefinitions: any): void {
for (const key in additionalDefinitions) {
if (baseDefinitions[key]) {
throw `Error: '${key}' defined in multiple schema files.`;
}
baseDefinitions[key] = additionalDefinitions[key];
}
}
export async function main() {
const packageJSON: any = JSON.parse(await read(resolve($root, 'package.json')));
const schemaJSON: any = JSON.parse(await read(resolve($root, 'tools/OptionsSchema.json')));
const symbolSettingsJSON: any = JSON.parse(await read(resolve($root, 'tools/VSSymbolSettings.json')));
mergeReferences(schemaJSON.definitions, symbolSettingsJSON.definitions);
schemaJSON.definitions = replaceReferences(schemaJSON.definitions, schemaJSON.definitions);
// Hard Code adding in configurationAttributes launch and attach.
// cppdbg
packageJSON.contributes.debuggers[0].configurationAttributes.launch = schemaJSON.definitions.CppdbgLaunchOptions;
packageJSON.contributes.debuggers[0].configurationAttributes.attach = schemaJSON.definitions.CppdbgAttachOptions;
// cppvsdbg
packageJSON.contributes.debuggers[1].configurationAttributes.launch = schemaJSON.definitions.CppvsdbgLaunchOptions;
packageJSON.contributes.debuggers[1].configurationAttributes.attach = schemaJSON.definitions.CppvsdbgAttachOptions;
let content: string = JSON.stringify(packageJSON, null, 4);
// We use '\u200b' (unicode zero-length space character) to break VS Code's URL detection regex for URLs that are examples. This process will
// convert that from the readable espace sequence, to just an invisible character. Convert it back to the visible espace sequence.
content = content.replace(/\u200b/gm, "\\u200b") + "\n";
await write('package.json', content);
}