5
5
*--------------------------------------------------------------------------------------------*/
6
6
'use strict' ;
7
7
8
- import { JSONSchema } from '../jsonSchema07' ;
8
+ import { JSONSchema , JSONSchemaMap , JSONSchemaRef } from '../jsonSchema07' ;
9
9
import { SchemaRequestService , WorkspaceContextService , PromiseConstructor , Thenable } from '../yamlLanguageService' ;
10
10
import { UnresolvedSchema , ResolvedSchema , JSONSchemaService ,
11
11
SchemaDependencies , FilePatternAssociation , ISchemaContributions } from 'vscode-json-languageservice/lib/umd/services/jsonSchemaService' ;
12
12
13
+ import * as nls from 'vscode-nls' ;
14
+ const localize = nls . loadMessageBundle ( ) ;
15
+
13
16
export declare type CustomSchemaProvider = ( uri : string ) => Thenable < string > ;
14
17
15
18
export class YAMLSchemaService extends JSONSchemaService {
16
19
17
20
private customSchemaProvider : CustomSchemaProvider | undefined ;
18
21
private filePatternAssociations : FilePatternAssociation [ ] ;
22
+ private contextService : WorkspaceContextService ;
19
23
20
24
constructor ( requestService : SchemaRequestService , contextService ?: WorkspaceContextService , promiseConstructor ?: PromiseConstructor ) {
21
25
super ( requestService , contextService , promiseConstructor ) ;
@@ -26,6 +30,135 @@ export class YAMLSchemaService extends JSONSchemaService {
26
30
this . customSchemaProvider = customSchemaProvider ;
27
31
}
28
32
33
+ //tslint:disable
34
+ public resolveSchemaContent ( schemaToResolve : UnresolvedSchema , schemaURL : string , dependencies : SchemaDependencies ) : Thenable < ResolvedSchema > {
35
+
36
+ let resolveErrors : string [ ] = schemaToResolve . errors . slice ( 0 ) ;
37
+ let schema = schemaToResolve . schema ;
38
+ let contextService = this . contextService ;
39
+
40
+ let findSection = ( schema : JSONSchema , path : string ) : any => {
41
+ if ( ! path ) {
42
+ return schema ;
43
+ }
44
+ let current : any = schema ;
45
+ if ( path [ 0 ] === '/' ) {
46
+ path = path . substr ( 1 ) ;
47
+ }
48
+ path . split ( '/' ) . some ( ( part ) => {
49
+ current = current [ part ] ;
50
+ return ! current ;
51
+ } ) ;
52
+ return current ;
53
+ } ;
54
+
55
+ let merge = ( target : JSONSchema , sourceRoot : JSONSchema , sourceURI : string , path : string ) : void => {
56
+ let section = findSection ( sourceRoot , path ) ;
57
+ if ( section ) {
58
+ for ( let key in section ) {
59
+ if ( section . hasOwnProperty ( key ) && ! target . hasOwnProperty ( key ) ) {
60
+ target [ key ] = section [ key ] ;
61
+ }
62
+ }
63
+ } else {
64
+ resolveErrors . push ( localize ( 'json.schema.invalidref' , '$ref \'{0}\' in \'{1}\' can not be resolved.' , path , sourceURI ) ) ;
65
+ }
66
+ } ;
67
+
68
+ let resolveExternalLink = ( node : JSONSchema , uri : string , linkPath : string , parentSchemaURL : string , parentSchemaDependencies : SchemaDependencies ) : Thenable < any > => {
69
+ if ( contextService && ! / ^ \w + : \/ \/ .* / . test ( uri ) ) {
70
+ uri = contextService . resolveRelativePath ( uri , parentSchemaURL ) ;
71
+ }
72
+ uri = this . normalizeId ( uri ) ;
73
+ const referencedHandle = this . getOrAddSchemaHandle ( uri ) ;
74
+ return referencedHandle . getUnresolvedSchema ( ) . then ( unresolvedSchema => {
75
+ parentSchemaDependencies [ uri ] = true ;
76
+ if ( unresolvedSchema . errors . length ) {
77
+ let loc = linkPath ? uri + '#' + linkPath : uri ;
78
+ resolveErrors . push ( localize ( 'json.schema.problemloadingref' , 'Problems loading reference \'{0}\': {1}' , loc , unresolvedSchema . errors [ 0 ] ) ) ;
79
+ }
80
+ merge ( node , unresolvedSchema . schema , uri , linkPath ) ;
81
+ return resolveRefs ( node , unresolvedSchema . schema , uri , referencedHandle . dependencies ) ;
82
+ } ) ;
83
+ } ;
84
+
85
+ let resolveRefs = ( node : JSONSchema , parentSchema : JSONSchema , parentSchemaURL : string , parentSchemaDependencies : SchemaDependencies ) : Thenable < any > => {
86
+ if ( ! node || typeof node !== 'object' ) {
87
+ return Promise . resolve ( null ) ;
88
+ }
89
+
90
+ let toWalk : JSONSchema [ ] = [ node ] ;
91
+ let seen : JSONSchema [ ] = [ ] ;
92
+
93
+ let openPromises : Thenable < any > [ ] = [ ] ;
94
+
95
+ let collectEntries = ( ...entries : JSONSchemaRef [ ] ) => {
96
+ for ( let entry of entries ) {
97
+ if ( typeof entry === 'object' ) {
98
+ toWalk . push ( entry ) ;
99
+ }
100
+ }
101
+ } ;
102
+ let collectMapEntries = ( ...maps : JSONSchemaMap [ ] ) => {
103
+ for ( let map of maps ) {
104
+ if ( typeof map === 'object' ) {
105
+ for ( let key in map ) {
106
+ let entry = map [ key ] ;
107
+ if ( typeof entry === 'object' ) {
108
+ toWalk . push ( entry ) ;
109
+ }
110
+ }
111
+ }
112
+ }
113
+ } ;
114
+ let collectArrayEntries = ( ...arrays : JSONSchemaRef [ ] [ ] ) => {
115
+ for ( let array of arrays ) {
116
+ if ( Array . isArray ( array ) ) {
117
+ for ( let entry of array ) {
118
+ if ( typeof entry === 'object' ) {
119
+ toWalk . push ( entry ) ;
120
+ }
121
+ }
122
+ }
123
+ }
124
+ } ;
125
+ let handleRef = ( next : JSONSchema ) => {
126
+ let seenRefs = [ ] ;
127
+ while ( next . $ref ) {
128
+ const ref = next . $ref ;
129
+ let segments = ref . split ( '#' , 2 ) ;
130
+ delete next . $ref ;
131
+ if ( segments [ 0 ] . length > 0 ) {
132
+ openPromises . push ( resolveExternalLink ( next , segments [ 0 ] , segments [ 1 ] , parentSchemaURL , parentSchemaDependencies ) ) ;
133
+ return ;
134
+ } else {
135
+ if ( seenRefs . indexOf ( ref ) === - 1 ) {
136
+ merge ( next , parentSchema , parentSchemaURL , segments [ 1 ] ) ; // can set next.$ref again, use seenRefs to avoid circle
137
+ seenRefs . push ( ref ) ;
138
+ }
139
+ }
140
+ }
141
+
142
+ collectEntries ( < JSONSchema > next . items , < JSONSchema > next . additionalProperties , next . not , next . contains , next . propertyNames , next . if , next . then , next . else ) ;
143
+ collectMapEntries ( next . definitions , next . properties , next . patternProperties , < JSONSchemaMap > next . dependencies ) ;
144
+ collectArrayEntries ( next . anyOf , next . allOf , next . oneOf , < JSONSchema [ ] > next . items , next . schemaSequence ) ;
145
+ } ;
146
+
147
+ while ( toWalk . length ) {
148
+ let next = toWalk . pop ( ) ;
149
+ if ( seen . indexOf ( next ) >= 0 ) {
150
+ continue ;
151
+ }
152
+ seen . push ( next ) ;
153
+ handleRef ( next ) ;
154
+ }
155
+ return Promise . all ( openPromises ) ;
156
+ } ;
157
+
158
+ return resolveRefs ( schema , schema , schemaURL , dependencies ) . then ( _ => new ResolvedSchema ( schema , resolveErrors ) ) ;
159
+ }
160
+ //tslint:enable
161
+
29
162
public getSchemaForResource ( resource : string , doc = undefined ) : Thenable < ResolvedSchema > {
30
163
const resolveSchema = ( ) => {
31
164
@@ -43,7 +176,12 @@ export class YAMLSchemaService extends JSONSchemaService {
43
176
}
44
177
45
178
if ( schemas . length > 0 ) {
46
- return super . createCombinedSchema ( resource , schemas ) . getResolvedSchema ( ) ;
179
+ return super . createCombinedSchema ( resource , schemas ) . getResolvedSchema ( ) . then ( schema => {
180
+ if ( schema . schema && schema . schema . schemaSequence && schema . schema . schemaSequence [ doc . currentDocIndex ] ) {
181
+ return new ResolvedSchema ( schema . schema . schemaSequence [ doc . currentDocIndex ] ) ;
182
+ }
183
+ return schema ;
184
+ } ) ;
47
185
}
48
186
49
187
return Promise . resolve ( null ) ;
@@ -56,7 +194,12 @@ export class YAMLSchemaService extends JSONSchemaService {
56
194
}
57
195
58
196
return this . loadSchema ( schemaUri )
59
- . then ( unsolvedSchema => this . resolveSchemaContent ( unsolvedSchema , schemaUri , [ ] ) ) ;
197
+ . then ( unsolvedSchema => this . resolveSchemaContent ( unsolvedSchema , schemaUri , [ ] ) . then ( schema => {
198
+ if ( schema . schema && schema . schema . schemaSequence && schema . schema . schemaSequence [ doc . currentDocIndex ] ) {
199
+ return new ResolvedSchema ( schema . schema . schemaSequence [ doc . currentDocIndex ] ) ;
200
+ }
201
+ return schema ;
202
+ } ) ) ;
60
203
} )
61
204
. then ( schema => schema , err => resolveSchema ( ) ) ;
62
205
} else {
@@ -69,8 +212,12 @@ export class YAMLSchemaService extends JSONSchemaService {
69
212
* to provide a wrapper around the javascript methods we are calling since they have no type
70
213
*/
71
214
72
- resolveSchemaContent ( schemaToResolve : UnresolvedSchema , schemaURL : string , dependencies : SchemaDependencies ) : Thenable < ResolvedSchema > {
73
- return super . resolveSchemaContent ( schemaToResolve , schemaURL , dependencies ) ;
215
+ normalizeId ( id : string ) {
216
+ return super . normalizeId ( id ) ;
217
+ }
218
+
219
+ getOrAddSchemaHandle ( id : string , unresolvedSchemaContent ?: JSONSchema ) {
220
+ return super . getOrAddSchemaHandle ( id , unresolvedSchemaContent ) ;
74
221
}
75
222
76
223
// tslint:disable-next-line: no-any
0 commit comments