in language-service/src/services/jsonSchemaService.ts [388:495]
public resolveSchemaContent(schemaToResolve: UnresolvedSchema, schemaURL: string): Thenable<ResolvedSchema> {
let resolveErrors: string[] = schemaToResolve.errors.slice(0);
let schema = schemaToResolve.schema;
let contextService = this.contextService;
let findSection = (schema: JSONSchema, path: string): any => {
if (!path) {
return schema;
}
let current: any = schema;
if (path[0] === '/') {
path = path.substr(1);
}
path.split('/').some((part) => {
current = current[part];
return !current;
});
return current;
};
let resolveLink = (node: any, linkedSchema: JSONSchema, linkPath: string): void => {
let section = findSection(linkedSchema, linkPath);
if (section) {
for (let key in section) {
if (section.hasOwnProperty(key) && !node.hasOwnProperty(key)) {
node[key] = section[key];
}
}
} else {
resolveErrors.push(localize('json.schema.invalidref', '$ref \'{0}\' in {1} can not be resolved.', linkPath, linkedSchema.id));
}
delete node.$ref;
};
let resolveExternalLink = (node: any, uri: string, linkPath: string, parentSchemaURL: string): Thenable<any> => {
if (contextService && !/^\w+:\/\/.*/.test(uri)) {
uri = contextService.resolveRelativePath(uri, parentSchemaURL);
}
uri = this.normalizeId(uri);
return this.getOrAddSchemaHandle(uri).getUnresolvedSchema().then(unresolvedSchema => {
if (unresolvedSchema.errors.length) {
let loc = linkPath ? uri + '#' + linkPath : uri;
resolveErrors.push(localize('json.schema.problemloadingref', 'Problems loading reference \'{0}\': {1}', loc, unresolvedSchema.errors[0]));
}
resolveLink(node, unresolvedSchema.schema, linkPath);
return resolveRefs(node, unresolvedSchema.schema, uri);
});
};
let resolveRefs = (node: JSONSchema, parentSchema: JSONSchema, parentSchemaURL: string): Thenable<any> => {
if (!node) {
return Promise.resolve(null);
}
let toWalk: JSONSchema[] = [node];
let seen: JSONSchema[] = [];
let openPromises: Thenable<any>[] = [];
let collectEntries = (...entries: JSONSchema[]) => {
for (let entry of entries) {
if (typeof entry === 'object') {
toWalk.push(entry);
}
}
};
let collectMapEntries = (...maps: JSONSchemaMap[]) => {
for (let map of maps) {
if (typeof map === 'object') {
for (let key in map) {
let entry = map[key];
toWalk.push(entry);
}
}
}
};
let collectArrayEntries = (...arrays: JSONSchema[][]) => {
for (let array of arrays) {
if (Array.isArray(array)) {
toWalk.push.apply(toWalk, array);
}
}
};
while (toWalk.length) {
let next = toWalk.pop();
if (seen.indexOf(next) >= 0) {
continue;
}
seen.push(next);
if (next.$ref) {
let segments = next.$ref.split('#', 2);
if (segments[0].length > 0) {
openPromises.push(resolveExternalLink(next, segments[0], segments[1], parentSchemaURL));
continue;
} else {
resolveLink(next, parentSchema, segments[1]);
}
}
collectEntries(next.items, next.additionalProperties, next.not);
collectMapEntries(next.definitions, next.properties, next.patternProperties, <JSONSchemaMap>next.dependencies);
collectArrayEntries(next.anyOf, next.allOf, next.oneOf, <JSONSchema[]>next.items);
}
return this.promise.all(openPromises);
};
return resolveRefs(schema, schema, schemaURL).then(_ => new ResolvedSchema(schema, resolveErrors));
}