vscode-json-languageservice 4.2.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -1
- package/SECURITY.md +41 -0
- package/lib/esm/jsonContributions.d.ts +17 -17
- package/lib/esm/jsonContributions.js +1 -1
- package/lib/esm/jsonLanguageService.d.ts +29 -29
- package/lib/esm/jsonLanguageService.js +66 -66
- package/lib/esm/jsonLanguageTypes.d.ts +279 -278
- package/lib/esm/jsonLanguageTypes.js +46 -45
- package/lib/esm/jsonSchema.d.ts +89 -70
- package/lib/esm/jsonSchema.js +1 -1
- package/lib/esm/parser/jsonParser.js +1214 -1218
- package/lib/esm/services/configuration.js +528 -528
- package/lib/esm/services/jsonCompletion.js +918 -934
- package/lib/esm/services/jsonDocumentSymbols.js +267 -278
- package/lib/esm/services/jsonFolding.js +120 -121
- package/lib/esm/services/jsonHover.js +109 -112
- package/lib/esm/services/jsonLinks.js +72 -73
- package/lib/esm/services/jsonSchemaService.js +586 -605
- package/lib/esm/services/jsonSelectionRanges.js +61 -61
- package/lib/esm/services/jsonValidation.js +151 -149
- package/lib/esm/utils/colors.js +68 -69
- package/lib/esm/utils/glob.js +124 -124
- package/lib/esm/utils/json.js +42 -42
- package/lib/esm/utils/objects.js +68 -65
- package/lib/esm/utils/strings.js +64 -64
- package/lib/umd/jsonContributions.d.ts +17 -17
- package/lib/umd/jsonContributions.js +12 -12
- package/lib/umd/jsonLanguageService.d.ts +29 -29
- package/lib/umd/jsonLanguageService.js +90 -90
- package/lib/umd/jsonLanguageTypes.d.ts +279 -278
- package/lib/umd/jsonLanguageTypes.js +93 -92
- package/lib/umd/jsonSchema.d.ts +89 -70
- package/lib/umd/jsonSchema.js +12 -12
- package/lib/umd/parser/jsonParser.js +1243 -1237
- package/lib/umd/services/configuration.js +541 -541
- package/lib/umd/services/jsonCompletion.js +932 -947
- package/lib/umd/services/jsonDocumentSymbols.js +281 -291
- package/lib/umd/services/jsonFolding.js +134 -135
- package/lib/umd/services/jsonHover.js +123 -125
- package/lib/umd/services/jsonLinks.js +86 -87
- package/lib/umd/services/jsonSchemaService.js +602 -618
- package/lib/umd/services/jsonSelectionRanges.js +75 -75
- package/lib/umd/services/jsonValidation.js +165 -162
- package/lib/umd/utils/colors.js +84 -85
- package/lib/umd/utils/glob.js +138 -138
- package/lib/umd/utils/json.js +56 -56
- package/lib/umd/utils/objects.js +87 -83
- package/lib/umd/utils/strings.js +82 -82
- package/package.json +10 -10
|
@@ -1,121 +1,120 @@
|
|
|
1
|
-
/*---------------------------------------------------------------------------------------------
|
|
2
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
-
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
|
-
*--------------------------------------------------------------------------------------------*/
|
|
5
|
-
import { createScanner } from 'jsonc-parser';
|
|
6
|
-
import { FoldingRangeKind, Position } from '../jsonLanguageTypes';
|
|
7
|
-
export function getFoldingRanges(document, context) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
function addRange(range) {
|
|
15
|
-
ranges.push(range);
|
|
16
|
-
nestingLevels.push(stack.length);
|
|
17
|
-
}
|
|
18
|
-
while (token !== 17 /* EOF */) {
|
|
19
|
-
switch (token) {
|
|
20
|
-
case 1 /* OpenBraceToken */:
|
|
21
|
-
case 3 /* OpenBracketToken */: {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
stack.push(range);
|
|
25
|
-
break;
|
|
26
|
-
}
|
|
27
|
-
case 2 /* CloseBraceToken */:
|
|
28
|
-
case 4 /* CloseBracketToken */: {
|
|
29
|
-
|
|
30
|
-
if (stack.length > 0 && stack[stack.length - 1].kind === kind) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (range && line > range.startLine + 1 && prevStart !== range.startLine) {
|
|
34
|
-
range.endLine = line - 1;
|
|
35
|
-
addRange(range);
|
|
36
|
-
prevStart = range.startLine;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
break;
|
|
40
|
-
}
|
|
41
|
-
case 13 /* BlockCommentTrivia */: {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (scanner.getTokenError() === 1 /* UnexpectedEndOfComment */ && startLine + 1 < document.lineCount) {
|
|
45
|
-
scanner.setPosition(document.offsetAt(Position.create(startLine + 1, 0)));
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
if (startLine < endLine) {
|
|
49
|
-
addRange({ startLine
|
|
50
|
-
prevStart = startLine;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
case 12 /* LineCommentTrivia */: {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (m) {
|
|
59
|
-
|
|
60
|
-
if (m[1]) { // start pattern match
|
|
61
|
-
|
|
62
|
-
stack.push(range);
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
|
|
66
|
-
while (i >= 0 && stack[i].kind !== FoldingRangeKind.Region) {
|
|
67
|
-
i--;
|
|
68
|
-
}
|
|
69
|
-
if (i >= 0) {
|
|
70
|
-
|
|
71
|
-
stack.length = i;
|
|
72
|
-
if (line > range.startLine && prevStart !== range.startLine) {
|
|
73
|
-
range.endLine = line;
|
|
74
|
-
addRange(range);
|
|
75
|
-
prevStart = range.startLine;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
break;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
token = scanner.scan();
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (typeof rangeLimit !== 'number' || ranges.length <= rangeLimit) {
|
|
87
|
-
return ranges;
|
|
88
|
-
}
|
|
89
|
-
if (context && context.onRangeLimitExceeded) {
|
|
90
|
-
context.onRangeLimitExceeded(document.uri);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
for (
|
|
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
|
-
}
|
|
1
|
+
/*---------------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
|
+
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
import { createScanner } from 'jsonc-parser';
|
|
6
|
+
import { FoldingRangeKind, Position } from '../jsonLanguageTypes';
|
|
7
|
+
export function getFoldingRanges(document, context) {
|
|
8
|
+
const ranges = [];
|
|
9
|
+
const nestingLevels = [];
|
|
10
|
+
const stack = [];
|
|
11
|
+
let prevStart = -1;
|
|
12
|
+
const scanner = createScanner(document.getText(), false);
|
|
13
|
+
let token = scanner.scan();
|
|
14
|
+
function addRange(range) {
|
|
15
|
+
ranges.push(range);
|
|
16
|
+
nestingLevels.push(stack.length);
|
|
17
|
+
}
|
|
18
|
+
while (token !== 17 /* EOF */) {
|
|
19
|
+
switch (token) {
|
|
20
|
+
case 1 /* OpenBraceToken */:
|
|
21
|
+
case 3 /* OpenBracketToken */: {
|
|
22
|
+
const startLine = document.positionAt(scanner.getTokenOffset()).line;
|
|
23
|
+
const range = { startLine, endLine: startLine, kind: token === 1 /* OpenBraceToken */ ? 'object' : 'array' };
|
|
24
|
+
stack.push(range);
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
case 2 /* CloseBraceToken */:
|
|
28
|
+
case 4 /* CloseBracketToken */: {
|
|
29
|
+
const kind = token === 2 /* CloseBraceToken */ ? 'object' : 'array';
|
|
30
|
+
if (stack.length > 0 && stack[stack.length - 1].kind === kind) {
|
|
31
|
+
const range = stack.pop();
|
|
32
|
+
const line = document.positionAt(scanner.getTokenOffset()).line;
|
|
33
|
+
if (range && line > range.startLine + 1 && prevStart !== range.startLine) {
|
|
34
|
+
range.endLine = line - 1;
|
|
35
|
+
addRange(range);
|
|
36
|
+
prevStart = range.startLine;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
case 13 /* BlockCommentTrivia */: {
|
|
42
|
+
const startLine = document.positionAt(scanner.getTokenOffset()).line;
|
|
43
|
+
const endLine = document.positionAt(scanner.getTokenOffset() + scanner.getTokenLength()).line;
|
|
44
|
+
if (scanner.getTokenError() === 1 /* UnexpectedEndOfComment */ && startLine + 1 < document.lineCount) {
|
|
45
|
+
scanner.setPosition(document.offsetAt(Position.create(startLine + 1, 0)));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
if (startLine < endLine) {
|
|
49
|
+
addRange({ startLine, endLine, kind: FoldingRangeKind.Comment });
|
|
50
|
+
prevStart = startLine;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
case 12 /* LineCommentTrivia */: {
|
|
56
|
+
const text = document.getText().substr(scanner.getTokenOffset(), scanner.getTokenLength());
|
|
57
|
+
const m = text.match(/^\/\/\s*#(region\b)|(endregion\b)/);
|
|
58
|
+
if (m) {
|
|
59
|
+
const line = document.positionAt(scanner.getTokenOffset()).line;
|
|
60
|
+
if (m[1]) { // start pattern match
|
|
61
|
+
const range = { startLine: line, endLine: line, kind: FoldingRangeKind.Region };
|
|
62
|
+
stack.push(range);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
let i = stack.length - 1;
|
|
66
|
+
while (i >= 0 && stack[i].kind !== FoldingRangeKind.Region) {
|
|
67
|
+
i--;
|
|
68
|
+
}
|
|
69
|
+
if (i >= 0) {
|
|
70
|
+
const range = stack[i];
|
|
71
|
+
stack.length = i;
|
|
72
|
+
if (line > range.startLine && prevStart !== range.startLine) {
|
|
73
|
+
range.endLine = line;
|
|
74
|
+
addRange(range);
|
|
75
|
+
prevStart = range.startLine;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
token = scanner.scan();
|
|
84
|
+
}
|
|
85
|
+
const rangeLimit = context && context.rangeLimit;
|
|
86
|
+
if (typeof rangeLimit !== 'number' || ranges.length <= rangeLimit) {
|
|
87
|
+
return ranges;
|
|
88
|
+
}
|
|
89
|
+
if (context && context.onRangeLimitExceeded) {
|
|
90
|
+
context.onRangeLimitExceeded(document.uri);
|
|
91
|
+
}
|
|
92
|
+
const counts = [];
|
|
93
|
+
for (let level of nestingLevels) {
|
|
94
|
+
if (level < 30) {
|
|
95
|
+
counts[level] = (counts[level] || 0) + 1;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
let entries = 0;
|
|
99
|
+
let maxLevel = 0;
|
|
100
|
+
for (let i = 0; i < counts.length; i++) {
|
|
101
|
+
const n = counts[i];
|
|
102
|
+
if (n) {
|
|
103
|
+
if (n + entries > rangeLimit) {
|
|
104
|
+
maxLevel = i;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
entries += n;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const result = [];
|
|
111
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
112
|
+
const level = nestingLevels[i];
|
|
113
|
+
if (typeof level === 'number') {
|
|
114
|
+
if (level < maxLevel || (level === maxLevel && entries++ < rangeLimit)) {
|
|
115
|
+
result.push(ranges[i]);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
@@ -1,112 +1,109 @@
|
|
|
1
|
-
/*---------------------------------------------------------------------------------------------
|
|
2
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
-
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
|
-
*--------------------------------------------------------------------------------------------*/
|
|
5
|
-
import * as Parser from '../parser/jsonParser';
|
|
6
|
-
import { Range } from '../jsonLanguageTypes';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
this.
|
|
11
|
-
this.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
node
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
var
|
|
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
|
-
return content;
|
|
112
|
-
}
|
|
1
|
+
/*---------------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
|
+
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
import * as Parser from '../parser/jsonParser';
|
|
6
|
+
import { Range } from '../jsonLanguageTypes';
|
|
7
|
+
export class JSONHover {
|
|
8
|
+
constructor(schemaService, contributions = [], promiseConstructor) {
|
|
9
|
+
this.schemaService = schemaService;
|
|
10
|
+
this.contributions = contributions;
|
|
11
|
+
this.promise = promiseConstructor || Promise;
|
|
12
|
+
}
|
|
13
|
+
doHover(document, position, doc) {
|
|
14
|
+
const offset = document.offsetAt(position);
|
|
15
|
+
let node = doc.getNodeFromOffset(offset);
|
|
16
|
+
if (!node || (node.type === 'object' || node.type === 'array') && offset > node.offset + 1 && offset < node.offset + node.length - 1) {
|
|
17
|
+
return this.promise.resolve(null);
|
|
18
|
+
}
|
|
19
|
+
const hoverRangeNode = node;
|
|
20
|
+
// use the property description when hovering over an object key
|
|
21
|
+
if (node.type === 'string') {
|
|
22
|
+
const parent = node.parent;
|
|
23
|
+
if (parent && parent.type === 'property' && parent.keyNode === node) {
|
|
24
|
+
node = parent.valueNode;
|
|
25
|
+
if (!node) {
|
|
26
|
+
return this.promise.resolve(null);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const hoverRange = Range.create(document.positionAt(hoverRangeNode.offset), document.positionAt(hoverRangeNode.offset + hoverRangeNode.length));
|
|
31
|
+
var createHover = (contents) => {
|
|
32
|
+
const result = {
|
|
33
|
+
contents: contents,
|
|
34
|
+
range: hoverRange
|
|
35
|
+
};
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
const location = Parser.getNodePath(node);
|
|
39
|
+
for (let i = this.contributions.length - 1; i >= 0; i--) {
|
|
40
|
+
const contribution = this.contributions[i];
|
|
41
|
+
const promise = contribution.getInfoContribution(document.uri, location);
|
|
42
|
+
if (promise) {
|
|
43
|
+
return promise.then(htmlContent => createHover(htmlContent));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return this.schemaService.getSchemaForResource(document.uri, doc).then((schema) => {
|
|
47
|
+
if (schema && node) {
|
|
48
|
+
const matchingSchemas = doc.getMatchingSchemas(schema.schema, node.offset);
|
|
49
|
+
let title = undefined;
|
|
50
|
+
let markdownDescription = undefined;
|
|
51
|
+
let markdownEnumValueDescription = undefined, enumValue = undefined;
|
|
52
|
+
matchingSchemas.every((s) => {
|
|
53
|
+
if (s.node === node && !s.inverted && s.schema) {
|
|
54
|
+
title = title || s.schema.title;
|
|
55
|
+
markdownDescription = markdownDescription || s.schema.markdownDescription || toMarkdown(s.schema.description);
|
|
56
|
+
if (s.schema.enum) {
|
|
57
|
+
const idx = s.schema.enum.indexOf(Parser.getNodeValue(node));
|
|
58
|
+
if (s.schema.markdownEnumDescriptions) {
|
|
59
|
+
markdownEnumValueDescription = s.schema.markdownEnumDescriptions[idx];
|
|
60
|
+
}
|
|
61
|
+
else if (s.schema.enumDescriptions) {
|
|
62
|
+
markdownEnumValueDescription = toMarkdown(s.schema.enumDescriptions[idx]);
|
|
63
|
+
}
|
|
64
|
+
if (markdownEnumValueDescription) {
|
|
65
|
+
enumValue = s.schema.enum[idx];
|
|
66
|
+
if (typeof enumValue !== 'string') {
|
|
67
|
+
enumValue = JSON.stringify(enumValue);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
});
|
|
74
|
+
let result = '';
|
|
75
|
+
if (title) {
|
|
76
|
+
result = toMarkdown(title);
|
|
77
|
+
}
|
|
78
|
+
if (markdownDescription) {
|
|
79
|
+
if (result.length > 0) {
|
|
80
|
+
result += "\n\n";
|
|
81
|
+
}
|
|
82
|
+
result += markdownDescription;
|
|
83
|
+
}
|
|
84
|
+
if (markdownEnumValueDescription) {
|
|
85
|
+
if (result.length > 0) {
|
|
86
|
+
result += "\n\n";
|
|
87
|
+
}
|
|
88
|
+
result += `\`${toMarkdownCodeBlock(enumValue)}\`: ${markdownEnumValueDescription}`;
|
|
89
|
+
}
|
|
90
|
+
return createHover([result]);
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function toMarkdown(plain) {
|
|
97
|
+
if (plain) {
|
|
98
|
+
const res = plain.replace(/([^\n\r])(\r?\n)([^\n\r])/gm, '$1\n\n$3'); // single new lines to \n\n (Markdown paragraph)
|
|
99
|
+
return res.replace(/[\\`*_{}[\]()#+\-.!]/g, "\\$&"); // escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
|
|
100
|
+
}
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
function toMarkdownCodeBlock(content) {
|
|
104
|
+
// see https://daringfireball.net/projects/markdown/syntax#precode
|
|
105
|
+
if (content.indexOf('`') !== -1) {
|
|
106
|
+
return '`` ' + content + ' ``';
|
|
107
|
+
}
|
|
108
|
+
return content;
|
|
109
|
+
}
|
|
@@ -1,73 +1,72 @@
|
|
|
1
|
-
/*---------------------------------------------------------------------------------------------
|
|
2
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
-
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
|
-
*--------------------------------------------------------------------------------------------*/
|
|
5
|
-
import { Range } from '../jsonLanguageTypes';
|
|
6
|
-
export function findLinks(document, doc) {
|
|
7
|
-
|
|
8
|
-
doc.visit(
|
|
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
|
-
}
|
|
1
|
+
/*---------------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
|
+
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
import { Range } from '../jsonLanguageTypes';
|
|
6
|
+
export function findLinks(document, doc) {
|
|
7
|
+
const links = [];
|
|
8
|
+
doc.visit(node => {
|
|
9
|
+
if (node.type === "property" && node.keyNode.value === "$ref" && node.valueNode?.type === 'string') {
|
|
10
|
+
const path = node.valueNode.value;
|
|
11
|
+
const targetNode = findTargetNode(doc, path);
|
|
12
|
+
if (targetNode) {
|
|
13
|
+
const targetPos = document.positionAt(targetNode.offset);
|
|
14
|
+
links.push({
|
|
15
|
+
target: `${document.uri}#${targetPos.line + 1},${targetPos.character + 1}`,
|
|
16
|
+
range: createRange(document, node.valueNode)
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
});
|
|
22
|
+
return Promise.resolve(links);
|
|
23
|
+
}
|
|
24
|
+
function createRange(document, node) {
|
|
25
|
+
return Range.create(document.positionAt(node.offset + 1), document.positionAt(node.offset + node.length - 1));
|
|
26
|
+
}
|
|
27
|
+
function findTargetNode(doc, path) {
|
|
28
|
+
const tokens = parseJSONPointer(path);
|
|
29
|
+
if (!tokens) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return findNode(tokens, doc.root);
|
|
33
|
+
}
|
|
34
|
+
function findNode(pointer, node) {
|
|
35
|
+
if (!node) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
if (pointer.length === 0) {
|
|
39
|
+
return node;
|
|
40
|
+
}
|
|
41
|
+
const token = pointer.shift();
|
|
42
|
+
if (node && node.type === 'object') {
|
|
43
|
+
const propertyNode = node.properties.find((propertyNode) => propertyNode.keyNode.value === token);
|
|
44
|
+
if (!propertyNode) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return findNode(pointer, propertyNode.valueNode);
|
|
48
|
+
}
|
|
49
|
+
else if (node && node.type === 'array') {
|
|
50
|
+
if (token.match(/^(0|[1-9][0-9]*)$/)) {
|
|
51
|
+
const index = Number.parseInt(token);
|
|
52
|
+
const arrayItem = node.items[index];
|
|
53
|
+
if (!arrayItem) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
return findNode(pointer, arrayItem);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
function parseJSONPointer(path) {
|
|
62
|
+
if (path === "#") {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
if (path[0] !== '#' || path[1] !== '/') {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return path.substring(2).split(/\//).map(unescape);
|
|
69
|
+
}
|
|
70
|
+
function unescape(str) {
|
|
71
|
+
return str.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
72
|
+
}
|