@swagger-api/apidom-parser-adapter-json 0.68.1
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 +373 -0
- package/LICENSES/Apache-2.0.txt +202 -0
- package/LICENSES/MIT.txt +9 -0
- package/NOTICE +57 -0
- package/README.md +125 -0
- package/cjs/adapter-browser.cjs +46 -0
- package/cjs/adapter-node.cjs +46 -0
- package/cjs/adapter.cjs +14 -0
- package/cjs/lexical-analysis/browser-patch.cjs +20 -0
- package/cjs/lexical-analysis/browser.cjs +42 -0
- package/cjs/lexical-analysis/node.cjs +21 -0
- package/cjs/media-types.cjs +14 -0
- package/cjs/syntactic-analysis/PreOrderCursorChildrenIterator.cjs +33 -0
- package/cjs/syntactic-analysis/PreOrderCusrorIterator.cjs +31 -0
- package/cjs/syntactic-analysis/direct/CursorIterator.cjs +110 -0
- package/cjs/syntactic-analysis/direct/index.cjs +228 -0
- package/cjs/syntactic-analysis/indirect/index.cjs +41 -0
- package/cjs/syntactic-analysis/indirect/visitors/CstVisitor.cjs +190 -0
- package/cjs/syntactic-analysis/indirect/visitors/JsonAstVisitor.cjs +186 -0
- package/dist/7c7ca323880d9fa6e48d1d1b2e78e140.wasm +0 -0
- package/dist/apidom-parser-adapter-json.browser.js +31014 -0
- package/dist/apidom-parser-adapter-json.browser.min.js +1 -0
- package/dist/fba0b3cc0d7ee926ea482deee298a5fe.wasm +0 -0
- package/es/adapter-browser.js +35 -0
- package/es/adapter-node.js +35 -0
- package/es/adapter.js +6 -0
- package/es/lexical-analysis/browser-patch.js +17 -0
- package/es/lexical-analysis/browser.js +36 -0
- package/es/lexical-analysis/node.js +14 -0
- package/es/media-types.js +8 -0
- package/es/syntactic-analysis/PreOrderCursorChildrenIterator.js +32 -0
- package/es/syntactic-analysis/PreOrderCusrorIterator.js +30 -0
- package/es/syntactic-analysis/direct/CursorIterator.js +104 -0
- package/es/syntactic-analysis/direct/index.js +227 -0
- package/es/syntactic-analysis/indirect/index.js +34 -0
- package/es/syntactic-analysis/indirect/visitors/CstVisitor.js +183 -0
- package/es/syntactic-analysis/indirect/visitors/JsonAstVisitor.js +180 -0
- package/package.json +81 -0
- package/types/dist.d.ts +53 -0
- package/wasm/tree-sitter-json.wasm +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime-corejs3/helpers/esm/defineProperty";
|
|
2
|
+
let _Symbol$iterator;
|
|
3
|
+
_Symbol$iterator = Symbol.iterator;
|
|
4
|
+
class PreOrderCursorChildrenIterator {
|
|
5
|
+
constructor(cursor) {
|
|
6
|
+
_defineProperty(this, "cursor", void 0);
|
|
7
|
+
this.cursor = cursor;
|
|
8
|
+
}
|
|
9
|
+
createNode() {
|
|
10
|
+
return {
|
|
11
|
+
type: this.cursor.nodeType,
|
|
12
|
+
startPosition: this.cursor.startPosition,
|
|
13
|
+
endPosition: this.cursor.endPosition,
|
|
14
|
+
children: []
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
*[_Symbol$iterator]() {
|
|
18
|
+
// @ts-ignore
|
|
19
|
+
const method = this[this.cursor.nodeType];
|
|
20
|
+
const currentNode = (method || this.createNode).call(this);
|
|
21
|
+
const constructor = this.constructor;
|
|
22
|
+
if (this.cursor.gotoFirstChild()) {
|
|
23
|
+
currentNode.children.push(...[...new constructor(this.cursor)]);
|
|
24
|
+
while (this.cursor.gotoNextSibling()) {
|
|
25
|
+
currentNode.children.push(...[...new constructor(this.cursor)]);
|
|
26
|
+
}
|
|
27
|
+
this.cursor.gotoParent();
|
|
28
|
+
}
|
|
29
|
+
yield currentNode;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export default PreOrderCursorChildrenIterator;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime-corejs3/helpers/esm/defineProperty";
|
|
2
|
+
let _Symbol$iterator;
|
|
3
|
+
_Symbol$iterator = Symbol.iterator;
|
|
4
|
+
class PreOrderCursorIterator {
|
|
5
|
+
constructor(cursor) {
|
|
6
|
+
_defineProperty(this, "cursor", void 0);
|
|
7
|
+
this.cursor = cursor;
|
|
8
|
+
}
|
|
9
|
+
createNode() {
|
|
10
|
+
return {
|
|
11
|
+
type: this.cursor.nodeType,
|
|
12
|
+
startPosition: this.cursor.startPosition,
|
|
13
|
+
endPosition: this.cursor.endPosition
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
*[_Symbol$iterator]() {
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
const method = this[this.cursor.nodeType];
|
|
19
|
+
const constructor = this.constructor;
|
|
20
|
+
yield (method || this.createNode).call(this);
|
|
21
|
+
if (this.cursor.gotoFirstChild()) {
|
|
22
|
+
yield* new constructor(this.cursor);
|
|
23
|
+
while (this.cursor.gotoNextSibling()) {
|
|
24
|
+
yield* new constructor(this.cursor);
|
|
25
|
+
}
|
|
26
|
+
this.cursor.gotoParent();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export default PreOrderCursorIterator;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import PreOrderCursorChildrenIterator from "../PreOrderCursorChildrenIterator.js";
|
|
2
|
+
class CursorIterator extends PreOrderCursorChildrenIterator {
|
|
3
|
+
document() {
|
|
4
|
+
return {
|
|
5
|
+
type: this.cursor.nodeType,
|
|
6
|
+
startPosition: this.cursor.startPosition,
|
|
7
|
+
endPosition: this.cursor.endPosition,
|
|
8
|
+
children: []
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
object() {
|
|
12
|
+
return {
|
|
13
|
+
type: this.cursor.nodeType,
|
|
14
|
+
startPosition: this.cursor.startPosition,
|
|
15
|
+
endPosition: this.cursor.endPosition,
|
|
16
|
+
fieldName: this.cursor.currentFieldName,
|
|
17
|
+
children: []
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
array() {
|
|
21
|
+
return {
|
|
22
|
+
type: this.cursor.nodeType,
|
|
23
|
+
startPosition: this.cursor.startPosition,
|
|
24
|
+
endPosition: this.cursor.endPosition,
|
|
25
|
+
fieldName: this.cursor.currentFieldName,
|
|
26
|
+
children: []
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
pair() {
|
|
30
|
+
return {
|
|
31
|
+
type: this.cursor.nodeType,
|
|
32
|
+
startPosition: this.cursor.startPosition,
|
|
33
|
+
endPosition: this.cursor.endPosition,
|
|
34
|
+
get keyNode() {
|
|
35
|
+
return this.children.find(node => node.fieldName === 'key');
|
|
36
|
+
},
|
|
37
|
+
get valueNode() {
|
|
38
|
+
return this.children.find(node => node.fieldName === 'value');
|
|
39
|
+
},
|
|
40
|
+
children: []
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
string() {
|
|
44
|
+
return {
|
|
45
|
+
type: this.cursor.nodeType,
|
|
46
|
+
startPosition: this.cursor.startPosition,
|
|
47
|
+
endPosition: this.cursor.endPosition,
|
|
48
|
+
text: this.cursor.nodeText,
|
|
49
|
+
fieldName: this.cursor.currentFieldName,
|
|
50
|
+
children: []
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
number() {
|
|
54
|
+
return {
|
|
55
|
+
type: this.cursor.nodeType,
|
|
56
|
+
startPosition: this.cursor.startPosition,
|
|
57
|
+
endPosition: this.cursor.endPosition,
|
|
58
|
+
text: this.cursor.nodeText,
|
|
59
|
+
fieldName: this.cursor.currentFieldName,
|
|
60
|
+
children: []
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
null() {
|
|
64
|
+
return {
|
|
65
|
+
type: this.cursor.nodeType,
|
|
66
|
+
startPosition: this.cursor.startPosition,
|
|
67
|
+
endPosition: this.cursor.endPosition,
|
|
68
|
+
fieldName: this.cursor.currentFieldName,
|
|
69
|
+
children: []
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
true() {
|
|
73
|
+
return {
|
|
74
|
+
type: this.cursor.nodeType,
|
|
75
|
+
startPosition: this.cursor.startPosition,
|
|
76
|
+
endPosition: this.cursor.endPosition,
|
|
77
|
+
fieldName: this.cursor.currentFieldName,
|
|
78
|
+
children: []
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
false() {
|
|
82
|
+
return {
|
|
83
|
+
type: this.cursor.nodeType,
|
|
84
|
+
startPosition: this.cursor.startPosition,
|
|
85
|
+
endPosition: this.cursor.endPosition,
|
|
86
|
+
fieldName: this.cursor.currentFieldName,
|
|
87
|
+
children: []
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
ERROR() {
|
|
91
|
+
const {
|
|
92
|
+
currentNode
|
|
93
|
+
} = this.cursor;
|
|
94
|
+
return {
|
|
95
|
+
type: this.cursor.nodeType,
|
|
96
|
+
startPosition: this.cursor.startPosition,
|
|
97
|
+
endPosition: this.cursor.endPosition,
|
|
98
|
+
// @ts-ignore
|
|
99
|
+
hasError: () => currentNode.hasError(),
|
|
100
|
+
children: []
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export default CursorIterator;
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime-corejs3/helpers/esm/defineProperty";
|
|
2
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
3
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
4
|
+
import stampit from 'stampit';
|
|
5
|
+
import { visit, getNodeType as getCSTNodeType, isNode as isCSTNode } from '@swagger-api/apidom-ast';
|
|
6
|
+
import { BooleanElement, NullElement, NumberElement, ParseResultElement, SourceMapElement, MemberElement, ObjectElement, ArrayElement, StringElement, AnnotationElement, isElement, isParseResultElement, isPrimitiveElement, keyMap as keyMapApiDOM, getNodeType as getNodeTypeApiDOM } from '@swagger-api/apidom-core';
|
|
7
|
+
|
|
8
|
+
/* eslint-disable no-underscore-dangle */
|
|
9
|
+
|
|
10
|
+
const keyMap = _objectSpread({
|
|
11
|
+
document: ['children'],
|
|
12
|
+
object: ['children'],
|
|
13
|
+
array: ['children'],
|
|
14
|
+
string: ['children'],
|
|
15
|
+
property: ['children'],
|
|
16
|
+
key: ['children'],
|
|
17
|
+
error: ['children']
|
|
18
|
+
}, keyMapApiDOM);
|
|
19
|
+
const getNodeType = node => {
|
|
20
|
+
if (isParseResultElement(node)) {
|
|
21
|
+
return 'ParseResultElement';
|
|
22
|
+
}
|
|
23
|
+
if (isElement(node)) {
|
|
24
|
+
return getNodeTypeApiDOM(node);
|
|
25
|
+
}
|
|
26
|
+
return getCSTNodeType(node);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
const isNode = element => isElement(element) || isCSTNode(element);
|
|
31
|
+
const Visitor = stampit({
|
|
32
|
+
props: {
|
|
33
|
+
sourceMap: false,
|
|
34
|
+
annotations: []
|
|
35
|
+
},
|
|
36
|
+
init() {
|
|
37
|
+
/**
|
|
38
|
+
* Private API.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
this.annotations = [];
|
|
42
|
+
const toPosition = node => {
|
|
43
|
+
if (node === null) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const start = new ArrayElement([node.startPosition.row, node.startPosition.column, node.startIndex]);
|
|
47
|
+
const end = new ArrayElement([node.endPosition.row, node.endPosition.column, node.endIndex]);
|
|
48
|
+
start.classes.push('position');
|
|
49
|
+
end.classes.push('position');
|
|
50
|
+
return [start, end];
|
|
51
|
+
};
|
|
52
|
+
const maybeAddSourceMap = (node, element) => {
|
|
53
|
+
if (!this.sourceMap) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const sourceMap = new SourceMapElement();
|
|
57
|
+
const position = toPosition(node);
|
|
58
|
+
if (position !== null) {
|
|
59
|
+
const [start, end] = position;
|
|
60
|
+
sourceMap.push(start);
|
|
61
|
+
sourceMap.push(end);
|
|
62
|
+
}
|
|
63
|
+
// @ts-ignore
|
|
64
|
+
sourceMap.astNode = node;
|
|
65
|
+
element.meta.set('sourceMap', sourceMap);
|
|
66
|
+
};
|
|
67
|
+
const getFieldFromNode = (fieldName, node) => {
|
|
68
|
+
var _node$childForFieldNa;
|
|
69
|
+
return `${fieldName}Node` in node ?
|
|
70
|
+
// @ts-ignore
|
|
71
|
+
node[`${fieldName}Node`] : 'childForFieldName' in node ? (_node$childForFieldNa = node.childForFieldName) === null || _node$childForFieldNa === void 0 ? void 0 : _node$childForFieldNa.call(node, fieldName) : null;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Public API.
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
this.enter = function enter(node) {
|
|
79
|
+
// missing anonymous literals from CST transformed into AnnotationElements.
|
|
80
|
+
// WARNING: be aware that web-tree-sitter and tree-sitter node bindings have inconsistency
|
|
81
|
+
// in `SyntaxNode.isNamed` property. web-tree-sitter has it defined as method
|
|
82
|
+
// whether tree-sitter node binding has it defined as a boolean property.
|
|
83
|
+
if ((typeof node.isNamed === 'function' && !node.isNamed() || node.isNamed === false) && node.isMissing()) {
|
|
84
|
+
// collect annotations from missing literals
|
|
85
|
+
const value = node.type || node.text;
|
|
86
|
+
const message = `(Missing ${value})`;
|
|
87
|
+
const element = new AnnotationElement(message);
|
|
88
|
+
element.classes.push('warning');
|
|
89
|
+
maybeAddSourceMap(node, element);
|
|
90
|
+
this.annotations.push(element);
|
|
91
|
+
}
|
|
92
|
+
return null; // remove everything unrecognized
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
this.document = function document(node) {
|
|
96
|
+
const element = new ParseResultElement();
|
|
97
|
+
// @ts-ignore
|
|
98
|
+
element._content = node.children;
|
|
99
|
+
maybeAddSourceMap(node, element);
|
|
100
|
+
return element;
|
|
101
|
+
};
|
|
102
|
+
this.ParseResultElement = {
|
|
103
|
+
leave(element) {
|
|
104
|
+
// mark first-non Annotation element as result
|
|
105
|
+
// @ts-ignore
|
|
106
|
+
const elements = element.findElements(isPrimitiveElement);
|
|
107
|
+
if (elements.length > 0) {
|
|
108
|
+
const resultElement = elements[0];
|
|
109
|
+
resultElement.classes.push('result');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// provide annotations
|
|
113
|
+
this.annotations.forEach(annotationElement => {
|
|
114
|
+
element.push(annotationElement);
|
|
115
|
+
});
|
|
116
|
+
this.annotations = [];
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
this.object = function object(node) {
|
|
120
|
+
const element = new ObjectElement();
|
|
121
|
+
// @ts-ignore
|
|
122
|
+
element._content = node.children;
|
|
123
|
+
maybeAddSourceMap(node, element);
|
|
124
|
+
return element;
|
|
125
|
+
};
|
|
126
|
+
this.array = function array(node) {
|
|
127
|
+
const element = new ArrayElement();
|
|
128
|
+
// @ts-ignore
|
|
129
|
+
element._content = node.children;
|
|
130
|
+
maybeAddSourceMap(node, element);
|
|
131
|
+
return element;
|
|
132
|
+
};
|
|
133
|
+
this.pair = function pair(node) {
|
|
134
|
+
const element = new MemberElement();
|
|
135
|
+
// @ts-ignore
|
|
136
|
+
element.content.key = getFieldFromNode('key', node);
|
|
137
|
+
// @ts-ignore
|
|
138
|
+
element.content.value = getFieldFromNode('value', node);
|
|
139
|
+
maybeAddSourceMap(node, element);
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Process possible errors here that may be present in pair node children as we're using direct field access.
|
|
143
|
+
* There are usually 3 children here found: "key", ":", "value".
|
|
144
|
+
*/
|
|
145
|
+
if (node.children.length > 3) {
|
|
146
|
+
node.children
|
|
147
|
+
// @ts-ignore
|
|
148
|
+
.filter(child => child.type === 'ERROR').forEach(errorNode => {
|
|
149
|
+
this.ERROR(errorNode, node, [], [node]);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
return element;
|
|
153
|
+
};
|
|
154
|
+
this.string = function string(node) {
|
|
155
|
+
const element = new StringElement(node.text.slice(1, -1));
|
|
156
|
+
maybeAddSourceMap(node, element);
|
|
157
|
+
return element;
|
|
158
|
+
};
|
|
159
|
+
this.number = function number(node) {
|
|
160
|
+
const element = new NumberElement(Number(node.text));
|
|
161
|
+
maybeAddSourceMap(node, element);
|
|
162
|
+
return element;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
166
|
+
this.null = function _null(node) {
|
|
167
|
+
const element = new NullElement();
|
|
168
|
+
maybeAddSourceMap(node, element);
|
|
169
|
+
return element;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
173
|
+
this.true = function _true(node) {
|
|
174
|
+
const element = new BooleanElement(true);
|
|
175
|
+
maybeAddSourceMap(node, element);
|
|
176
|
+
return element;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
180
|
+
this.false = function _false(node) {
|
|
181
|
+
const element = new BooleanElement(false);
|
|
182
|
+
maybeAddSourceMap(node, element);
|
|
183
|
+
return element;
|
|
184
|
+
};
|
|
185
|
+
this.ERROR = function ERROR(node, key, parent, path) {
|
|
186
|
+
// collect errors as annotations
|
|
187
|
+
const isUnexpected = !node.hasError();
|
|
188
|
+
const value = node.text;
|
|
189
|
+
const message = isUnexpected ? `(Unexpected ${value})` : `(Error ${value})`;
|
|
190
|
+
const element = new AnnotationElement(message);
|
|
191
|
+
element.classes.push('error');
|
|
192
|
+
maybeAddSourceMap(node, element);
|
|
193
|
+
if (path.length === 0) {
|
|
194
|
+
// no document to visit, only error is present in CST
|
|
195
|
+
const parseResultElement = new ParseResultElement();
|
|
196
|
+
parseResultElement.push(element);
|
|
197
|
+
return parseResultElement;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// we have CST node for document
|
|
201
|
+
this.annotations.push(element);
|
|
202
|
+
return null;
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* This version of syntactic analysis translates TreeSitter CTS into ApiDOM.
|
|
209
|
+
* Single traversal pass is needed to get from CST to ApiDOM.
|
|
210
|
+
*/
|
|
211
|
+
const analyze = (cst, {
|
|
212
|
+
sourceMap = false
|
|
213
|
+
} = {}) => {
|
|
214
|
+
const visitor = Visitor();
|
|
215
|
+
return visit(cst.rootNode, visitor, {
|
|
216
|
+
// @ts-ignore
|
|
217
|
+
keyMap,
|
|
218
|
+
// @ts-ignore
|
|
219
|
+
nodeTypeGetter: getNodeType,
|
|
220
|
+
// @ts-ignore
|
|
221
|
+
nodePredicate: isNode,
|
|
222
|
+
state: {
|
|
223
|
+
sourceMap
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
export default analyze;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { visit } from '@swagger-api/apidom-ast';
|
|
2
|
+
import CstVisitor, { keyMap as cstKeyMap } from "./visitors/CstVisitor.js";
|
|
3
|
+
import JsonAstVisitor, { keyMap as astKeyMap, isNode, getNodeType } from "./visitors/JsonAstVisitor.js";
|
|
4
|
+
/**
|
|
5
|
+
* This version of syntactic analysis does following transformations:
|
|
6
|
+
* TreeSitter CST -> JSON AST -> ApiDOM
|
|
7
|
+
* Two traversals passes are needed to get from CST to ApiDOM.
|
|
8
|
+
* This analysis is much slower than the direct one, but allows
|
|
9
|
+
* to do additional analysis magic on JSON AST.
|
|
10
|
+
*/
|
|
11
|
+
const analyze = (cst, {
|
|
12
|
+
sourceMap = false
|
|
13
|
+
} = {}) => {
|
|
14
|
+
const cstVisitor = CstVisitor();
|
|
15
|
+
const astVisitor = JsonAstVisitor();
|
|
16
|
+
const jsonAst = visit(cst.rootNode, cstVisitor, {
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
keyMap: cstKeyMap,
|
|
19
|
+
state: {
|
|
20
|
+
sourceMap
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
return visit(jsonAst.rootNode, astVisitor, {
|
|
24
|
+
// @ts-ignore
|
|
25
|
+
keyMap: astKeyMap,
|
|
26
|
+
// @ts-ignore
|
|
27
|
+
nodeTypeGetter: getNodeType,
|
|
28
|
+
nodePredicate: isNode,
|
|
29
|
+
state: {
|
|
30
|
+
sourceMap
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
export default analyze;
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import stampit from 'stampit';
|
|
2
|
+
import { JsonArray, JsonDocument, JsonFalse, JsonNull, JsonNumber, JsonObject, JsonKey, JsonProperty, JsonString, JsonStringContent, JsonTrue, ParseResult, Position, Point, Literal, Error } from '@swagger-api/apidom-ast';
|
|
3
|
+
export const keyMap = {
|
|
4
|
+
document: ['children'],
|
|
5
|
+
object: ['children'],
|
|
6
|
+
array: ['children'],
|
|
7
|
+
string: ['children'],
|
|
8
|
+
property: ['children'],
|
|
9
|
+
key: ['children'],
|
|
10
|
+
error: ['children']
|
|
11
|
+
};
|
|
12
|
+
const CstVisitor = stampit({
|
|
13
|
+
init() {
|
|
14
|
+
/**
|
|
15
|
+
* Private API.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const toPosition = node => {
|
|
19
|
+
if (node === null) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const start = Point({
|
|
23
|
+
row: node.startPosition.row,
|
|
24
|
+
column: node.startPosition.column,
|
|
25
|
+
char: node.startIndex
|
|
26
|
+
});
|
|
27
|
+
const end = Point({
|
|
28
|
+
row: node.endPosition.row,
|
|
29
|
+
column: node.endPosition.column,
|
|
30
|
+
char: node.endIndex
|
|
31
|
+
});
|
|
32
|
+
return Position({
|
|
33
|
+
start,
|
|
34
|
+
end
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
const getFieldFromNode = (fieldName, node) => {
|
|
38
|
+
var _node$childForFieldNa;
|
|
39
|
+
return `${fieldName}Node` in node ?
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
node[`${fieldName}Node`] : 'childForFieldName' in node ? (_node$childForFieldNa = node.childForFieldName) === null || _node$childForFieldNa === void 0 ? void 0 : _node$childForFieldNa.call(node, fieldName) : null;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Public API.
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
this.enter = function enter(node) {
|
|
49
|
+
// missing anonymous literals from CST transformed into AST literal nodes
|
|
50
|
+
// WARNING: be aware that web-tree-sitter and tree-sitter node bindings have inconsistency
|
|
51
|
+
// in `SyntaxNode.isNamed` property. web-tree-sitter has it defined as method
|
|
52
|
+
// whether tree-sitter node binding has it defined as a boolean property.
|
|
53
|
+
// @ts-ignore
|
|
54
|
+
if (typeof node.isNamed === 'function' && !node.isNamed() || node.isNamed === false) {
|
|
55
|
+
const position = toPosition(node);
|
|
56
|
+
const value = node.type || node.text;
|
|
57
|
+
const isMissing = node.isMissing();
|
|
58
|
+
return Literal({
|
|
59
|
+
value,
|
|
60
|
+
position,
|
|
61
|
+
isMissing
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return undefined;
|
|
65
|
+
};
|
|
66
|
+
this.document = {
|
|
67
|
+
enter(node) {
|
|
68
|
+
const position = toPosition(node);
|
|
69
|
+
return JsonDocument({
|
|
70
|
+
children: node.children,
|
|
71
|
+
position,
|
|
72
|
+
isMissing: node.isMissing()
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
leave(document) {
|
|
76
|
+
return ParseResult({
|
|
77
|
+
children: [document]
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
this.object = function object(node) {
|
|
82
|
+
const position = toPosition(node);
|
|
83
|
+
return JsonObject({
|
|
84
|
+
children: node.children,
|
|
85
|
+
position,
|
|
86
|
+
isMissing: node.isMissing()
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
this.pair = function pair(node) {
|
|
90
|
+
const position = toPosition(node);
|
|
91
|
+
const children = node.children.slice(1);
|
|
92
|
+
const keyNode = getFieldFromNode('key', node);
|
|
93
|
+
const key = JsonKey({
|
|
94
|
+
children: (keyNode === null || keyNode === void 0 ? void 0 : keyNode.children) || [],
|
|
95
|
+
position: toPosition(keyNode),
|
|
96
|
+
isMissing: (keyNode === null || keyNode === void 0 ? void 0 : keyNode.isMissing()) || false
|
|
97
|
+
});
|
|
98
|
+
return JsonProperty({
|
|
99
|
+
children: [key, ...children],
|
|
100
|
+
position,
|
|
101
|
+
isMissing: node.isMissing()
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
this.array = function array(node) {
|
|
105
|
+
const position = toPosition(node);
|
|
106
|
+
return JsonArray({
|
|
107
|
+
children: node.children,
|
|
108
|
+
position,
|
|
109
|
+
isMissing: node.isMissing()
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
this.string = function string(node) {
|
|
113
|
+
const position = toPosition(node);
|
|
114
|
+
const content = JsonStringContent({
|
|
115
|
+
value: node.text.slice(1, -1)
|
|
116
|
+
});
|
|
117
|
+
return JsonString({
|
|
118
|
+
children: [content],
|
|
119
|
+
position,
|
|
120
|
+
isMissing: node.isMissing()
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
this.number = function number(node) {
|
|
124
|
+
const position = toPosition(node);
|
|
125
|
+
const value = node.text;
|
|
126
|
+
return JsonNumber({
|
|
127
|
+
value,
|
|
128
|
+
position,
|
|
129
|
+
isMissing: node.isMissing()
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
134
|
+
this.null = function _null(node) {
|
|
135
|
+
const position = toPosition(node);
|
|
136
|
+
const value = node.text;
|
|
137
|
+
return JsonNull({
|
|
138
|
+
value,
|
|
139
|
+
position,
|
|
140
|
+
isMissing: node.isMissing()
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
145
|
+
this.true = function _true(node) {
|
|
146
|
+
const position = toPosition(node);
|
|
147
|
+
const value = node.text;
|
|
148
|
+
return JsonTrue({
|
|
149
|
+
value,
|
|
150
|
+
position,
|
|
151
|
+
isMissing: node.isMissing()
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
156
|
+
this.false = function _false(node) {
|
|
157
|
+
const position = toPosition(node);
|
|
158
|
+
const value = node.text;
|
|
159
|
+
return JsonFalse({
|
|
160
|
+
value,
|
|
161
|
+
position,
|
|
162
|
+
isMissing: node.isMissing()
|
|
163
|
+
});
|
|
164
|
+
};
|
|
165
|
+
this.ERROR = function ERROR(node, key, parent, path) {
|
|
166
|
+
const position = toPosition(node);
|
|
167
|
+
const errorNode = Error({
|
|
168
|
+
children: node.children,
|
|
169
|
+
position,
|
|
170
|
+
isUnexpected: !node.hasError(),
|
|
171
|
+
isMissing: node.isMissing(),
|
|
172
|
+
value: node.text
|
|
173
|
+
});
|
|
174
|
+
if (path.length === 0) {
|
|
175
|
+
return ParseResult({
|
|
176
|
+
children: [errorNode]
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
return errorNode;
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
export default CstVisitor;
|