@swagger-api/apidom-parser-adapter-json 0.70.3 → 0.71.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 +19 -0
- package/cjs/syntactic-analysis/TreeCursorIterator.cjs +62 -0
- package/cjs/syntactic-analysis/TreeCursorSyntaxNode.cjs +51 -0
- package/cjs/syntactic-analysis/direct/index.cjs +17 -183
- package/cjs/syntactic-analysis/direct/visitors/CstVisitor.cjs +175 -0
- package/cjs/syntactic-analysis/indirect/index.cjs +14 -2
- package/cjs/syntactic-analysis/indirect/visitors/CstVisitor.cjs +23 -31
- package/dist/apidom-parser-adapter-json.browser.js +463 -337
- package/dist/apidom-parser-adapter-json.browser.min.js +1 -1
- package/es/syntactic-analysis/TreeCursorIterator.js +60 -0
- package/es/syntactic-analysis/TreeCursorSyntaxNode.js +56 -0
- package/es/syntactic-analysis/direct/index.js +18 -185
- package/es/syntactic-analysis/direct/visitors/CstVisitor.js +169 -0
- package/es/syntactic-analysis/indirect/index.js +13 -2
- package/es/syntactic-analysis/indirect/visitors/CstVisitor.js +23 -31
- package/package.json +5 -5
- package/types/dist.d.ts +19 -4
- package/cjs/syntactic-analysis/PreOrderCursorChildrenIterator.cjs +0 -33
- package/cjs/syntactic-analysis/PreOrderCusrorIterator.cjs +0 -31
- package/cjs/syntactic-analysis/direct/CursorIterator.cjs +0 -110
- package/es/syntactic-analysis/PreOrderCursorChildrenIterator.js +0 -32
- package/es/syntactic-analysis/PreOrderCusrorIterator.js +0 -30
- package/es/syntactic-analysis/direct/CursorIterator.js +0 -104
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [0.71.0](https://github.com/swagger-api/apidom/compare/v0.70.4...v0.71.0) (2023-07-13)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @swagger-api/apidom-parser-adapter-json
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [0.70.4](https://github.com/swagger-api/apidom/compare/v0.70.3...v0.70.4) (2023-06-28)
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
- **parser-adapter-json:** construct proper JavaScript string value ([#2896](https://github.com/swagger-api/apidom/issues/2896)) ([fcdd3d5](https://github.com/swagger-api/apidom/commit/fcdd3d5144fe74eb5a05af20a1f8ddb1c9411ae4)), closes [#2670](https://github.com/swagger-api/apidom/issues/2670)
|
|
19
|
+
|
|
20
|
+
### Performance Improvements
|
|
21
|
+
|
|
22
|
+
- **parser-adapter-json:** use tree-sitter cursor for CST traversal ([#2891](https://github.com/swagger-api/apidom/issues/2891)) ([13a8567](https://github.com/swagger-api/apidom/commit/13a85672e8ae158ce635d5b52b6828180876d21c)), closes [#691](https://github.com/swagger-api/apidom/issues/691)
|
|
23
|
+
- **parser-adapter-json:** use tree-sitter cursor for CST traversal (indirect) ([#2895](https://github.com/swagger-api/apidom/issues/2895)) ([3f9c9a2](https://github.com/swagger-api/apidom/commit/3f9c9a2fbbfd4afdcf17cdce34523c0229444b15)), closes [#691](https://github.com/swagger-api/apidom/issues/691)
|
|
24
|
+
|
|
6
25
|
## [0.70.3](https://github.com/swagger-api/apidom/compare/v0.70.2...v0.70.3) (2023-06-27)
|
|
7
26
|
|
|
8
27
|
### Bug Fixes
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
|
|
4
|
+
exports.__esModule = true;
|
|
5
|
+
exports.default = void 0;
|
|
6
|
+
var _TreeCursorSyntaxNode = _interopRequireDefault(require("./TreeCursorSyntaxNode.cjs"));
|
|
7
|
+
class TreeCursorIterator {
|
|
8
|
+
constructor(cursor) {
|
|
9
|
+
this.cursor = cursor;
|
|
10
|
+
}
|
|
11
|
+
document() {
|
|
12
|
+
return new _TreeCursorSyntaxNode.default(this.cursor);
|
|
13
|
+
}
|
|
14
|
+
object() {
|
|
15
|
+
return new _TreeCursorSyntaxNode.default(this.cursor).setFieldName(this.cursor);
|
|
16
|
+
}
|
|
17
|
+
array() {
|
|
18
|
+
return new _TreeCursorSyntaxNode.default(this.cursor).setFieldName(this.cursor);
|
|
19
|
+
}
|
|
20
|
+
pair() {
|
|
21
|
+
return new _TreeCursorSyntaxNode.default(this.cursor);
|
|
22
|
+
}
|
|
23
|
+
string() {
|
|
24
|
+
return new _TreeCursorSyntaxNode.default(this.cursor).setFieldName(this.cursor);
|
|
25
|
+
}
|
|
26
|
+
number() {
|
|
27
|
+
return new _TreeCursorSyntaxNode.default(this.cursor).setFieldName(this.cursor);
|
|
28
|
+
}
|
|
29
|
+
null() {
|
|
30
|
+
return new _TreeCursorSyntaxNode.default(this.cursor).setFieldName(this.cursor);
|
|
31
|
+
}
|
|
32
|
+
true() {
|
|
33
|
+
return new _TreeCursorSyntaxNode.default(this.cursor).setFieldName(this.cursor);
|
|
34
|
+
}
|
|
35
|
+
false() {
|
|
36
|
+
return new _TreeCursorSyntaxNode.default(this.cursor).setFieldName(this.cursor);
|
|
37
|
+
}
|
|
38
|
+
ERROR() {
|
|
39
|
+
return new _TreeCursorSyntaxNode.default(this.cursor).setHasError(this.cursor);
|
|
40
|
+
}
|
|
41
|
+
*[Symbol.iterator]() {
|
|
42
|
+
let node;
|
|
43
|
+
if (this.cursor.nodeType in this) {
|
|
44
|
+
// @ts-ignore
|
|
45
|
+
node = this[this.cursor.nodeType]();
|
|
46
|
+
} else {
|
|
47
|
+
node = new _TreeCursorSyntaxNode.default(this.cursor);
|
|
48
|
+
}
|
|
49
|
+
if (this.cursor.gotoFirstChild()) {
|
|
50
|
+
const [firstChild] = new TreeCursorIterator(this.cursor);
|
|
51
|
+
node.pushChildren(firstChild);
|
|
52
|
+
while (this.cursor.gotoNextSibling()) {
|
|
53
|
+
const firstChildSiblings = new TreeCursorIterator(this.cursor);
|
|
54
|
+
node.pushChildren(...firstChildSiblings);
|
|
55
|
+
}
|
|
56
|
+
this.cursor.gotoParent();
|
|
57
|
+
}
|
|
58
|
+
yield node;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
var _default = TreeCursorIterator;
|
|
62
|
+
exports.default = _default;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.default = void 0;
|
|
5
|
+
class TreeCursorSyntaxNode {
|
|
6
|
+
hasError = false;
|
|
7
|
+
children = [];
|
|
8
|
+
constructor(cursor) {
|
|
9
|
+
this.type = cursor.nodeType;
|
|
10
|
+
this.startPosition = cursor.startPosition;
|
|
11
|
+
this.endPosition = cursor.endPosition;
|
|
12
|
+
this.startIndex = cursor.startIndex;
|
|
13
|
+
this.endIndex = cursor.endIndex;
|
|
14
|
+
this.text = cursor.nodeText;
|
|
15
|
+
this.isNamed = cursor.nodeIsNamed;
|
|
16
|
+
this.isMissing = cursor.nodeIsMissing;
|
|
17
|
+
}
|
|
18
|
+
get keyNode() {
|
|
19
|
+
if (this.type === 'pair') {
|
|
20
|
+
return this.children.find(node => node.fieldName === 'key');
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
get valueNode() {
|
|
25
|
+
if (this.type === 'pair') {
|
|
26
|
+
return this.children.find(node => node.fieldName === 'value');
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
setFieldName(cursor) {
|
|
31
|
+
if (typeof cursor.currentFieldName === 'function') {
|
|
32
|
+
this.fieldName = cursor.currentFieldName();
|
|
33
|
+
} else {
|
|
34
|
+
this.fieldName = cursor.currentFieldName;
|
|
35
|
+
}
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
setHasError(cursor) {
|
|
39
|
+
if (typeof cursor.currentNode === 'function') {
|
|
40
|
+
this.hasError = cursor.currentNode().hasError();
|
|
41
|
+
} else {
|
|
42
|
+
this.hasError = cursor.currentNode.hasError();
|
|
43
|
+
}
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
pushChildren(...children) {
|
|
47
|
+
this.children.push(...children);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
var _default = TreeCursorSyntaxNode;
|
|
51
|
+
exports.default = _default;
|
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
|
|
4
4
|
exports.__esModule = true;
|
|
5
5
|
exports.default = void 0;
|
|
6
|
-
var _stampit = _interopRequireDefault(require("stampit"));
|
|
7
6
|
var _apidomAst = require("@swagger-api/apidom-ast");
|
|
8
7
|
var _apidomCore = require("@swagger-api/apidom-core");
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
var _CstVisitor = _interopRequireDefault(require("./visitors/CstVisitor.cjs"));
|
|
9
|
+
var _TreeCursorIterator = _interopRequireDefault(require("../TreeCursorIterator.cjs"));
|
|
11
10
|
const keyMap = {
|
|
12
11
|
document: ['children'],
|
|
13
12
|
object: ['children'],
|
|
@@ -30,196 +29,31 @@ const getNodeType = node => {
|
|
|
30
29
|
|
|
31
30
|
// @ts-ignore
|
|
32
31
|
const isNode = element => (0, _apidomCore.isElement)(element) || (0, _apidomAst.isNode)(element);
|
|
33
|
-
const Visitor = (0, _stampit.default)({
|
|
34
|
-
props: {
|
|
35
|
-
sourceMap: false,
|
|
36
|
-
annotations: []
|
|
37
|
-
},
|
|
38
|
-
init() {
|
|
39
|
-
/**
|
|
40
|
-
* Private API.
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
this.annotations = [];
|
|
44
|
-
const toPosition = node => {
|
|
45
|
-
if (node === null) {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
const start = new _apidomCore.ArrayElement([node.startPosition.row, node.startPosition.column, node.startIndex]);
|
|
49
|
-
const end = new _apidomCore.ArrayElement([node.endPosition.row, node.endPosition.column, node.endIndex]);
|
|
50
|
-
start.classes.push('position');
|
|
51
|
-
end.classes.push('position');
|
|
52
|
-
return [start, end];
|
|
53
|
-
};
|
|
54
|
-
const maybeAddSourceMap = (node, element) => {
|
|
55
|
-
if (!this.sourceMap) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
const sourceMap = new _apidomCore.SourceMapElement();
|
|
59
|
-
const position = toPosition(node);
|
|
60
|
-
if (position !== null) {
|
|
61
|
-
const [start, end] = position;
|
|
62
|
-
sourceMap.push(start);
|
|
63
|
-
sourceMap.push(end);
|
|
64
|
-
}
|
|
65
|
-
// @ts-ignore
|
|
66
|
-
sourceMap.astNode = node;
|
|
67
|
-
element.meta.set('sourceMap', sourceMap);
|
|
68
|
-
};
|
|
69
|
-
const getFieldFromNode = (fieldName, node) => {
|
|
70
|
-
var _node$childForFieldNa;
|
|
71
|
-
return `${fieldName}Node` in node ?
|
|
72
|
-
// @ts-ignore
|
|
73
|
-
node[`${fieldName}Node`] : 'childForFieldName' in node ? (_node$childForFieldNa = node.childForFieldName) === null || _node$childForFieldNa === void 0 ? void 0 : _node$childForFieldNa.call(node, fieldName) : null;
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Public API.
|
|
78
|
-
*/
|
|
79
|
-
|
|
80
|
-
this.enter = function enter(node) {
|
|
81
|
-
// missing anonymous literals from CST transformed into AnnotationElements.
|
|
82
|
-
// WARNING: be aware that web-tree-sitter and tree-sitter node bindings have inconsistency
|
|
83
|
-
// in `SyntaxNode.isNamed` property. web-tree-sitter has it defined as method
|
|
84
|
-
// whether tree-sitter node binding has it defined as a boolean property.
|
|
85
|
-
if ((typeof node.isNamed === 'function' && !node.isNamed() || node.isNamed === false) && node.isMissing()) {
|
|
86
|
-
// collect annotations from missing literals
|
|
87
|
-
const value = node.type || node.text;
|
|
88
|
-
const message = `(Missing ${value})`;
|
|
89
|
-
const element = new _apidomCore.AnnotationElement(message);
|
|
90
|
-
element.classes.push('warning');
|
|
91
|
-
maybeAddSourceMap(node, element);
|
|
92
|
-
this.annotations.push(element);
|
|
93
|
-
}
|
|
94
|
-
return null; // remove everything unrecognized
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
this.document = function document(node) {
|
|
98
|
-
const element = new _apidomCore.ParseResultElement();
|
|
99
|
-
// @ts-ignore
|
|
100
|
-
element._content = node.children;
|
|
101
|
-
maybeAddSourceMap(node, element);
|
|
102
|
-
return element;
|
|
103
|
-
};
|
|
104
|
-
this.ParseResultElement = {
|
|
105
|
-
leave(element) {
|
|
106
|
-
// mark first-non Annotation element as result
|
|
107
|
-
// @ts-ignore
|
|
108
|
-
const elements = element.findElements(_apidomCore.isPrimitiveElement);
|
|
109
|
-
if (elements.length > 0) {
|
|
110
|
-
const resultElement = elements[0];
|
|
111
|
-
resultElement.classes.push('result');
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// provide annotations
|
|
115
|
-
this.annotations.forEach(annotationElement => {
|
|
116
|
-
element.push(annotationElement);
|
|
117
|
-
});
|
|
118
|
-
this.annotations = [];
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
this.object = function object(node) {
|
|
122
|
-
const element = new _apidomCore.ObjectElement();
|
|
123
|
-
// @ts-ignore
|
|
124
|
-
element._content = node.children;
|
|
125
|
-
maybeAddSourceMap(node, element);
|
|
126
|
-
return element;
|
|
127
|
-
};
|
|
128
|
-
this.array = function array(node) {
|
|
129
|
-
const element = new _apidomCore.ArrayElement();
|
|
130
|
-
// @ts-ignore
|
|
131
|
-
element._content = node.children;
|
|
132
|
-
maybeAddSourceMap(node, element);
|
|
133
|
-
return element;
|
|
134
|
-
};
|
|
135
|
-
this.pair = function pair(node) {
|
|
136
|
-
const element = new _apidomCore.MemberElement();
|
|
137
|
-
// @ts-ignore
|
|
138
|
-
element.content.key = getFieldFromNode('key', node);
|
|
139
|
-
// @ts-ignore
|
|
140
|
-
element.content.value = getFieldFromNode('value', node);
|
|
141
|
-
maybeAddSourceMap(node, element);
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Process possible errors here that may be present in pair node children as we're using direct field access.
|
|
145
|
-
* There are usually 3 children here found: "key", ":", "value".
|
|
146
|
-
*/
|
|
147
|
-
if (node.children.length > 3) {
|
|
148
|
-
node.children
|
|
149
|
-
// @ts-ignore
|
|
150
|
-
.filter(child => child.type === 'ERROR').forEach(errorNode => {
|
|
151
|
-
this.ERROR(errorNode, node, [], [node]);
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
return element;
|
|
155
|
-
};
|
|
156
|
-
this.string = function string(node) {
|
|
157
|
-
const element = new _apidomCore.StringElement(node.text.slice(1, -1));
|
|
158
|
-
maybeAddSourceMap(node, element);
|
|
159
|
-
return element;
|
|
160
|
-
};
|
|
161
|
-
this.number = function number(node) {
|
|
162
|
-
const element = new _apidomCore.NumberElement(Number(node.text));
|
|
163
|
-
maybeAddSourceMap(node, element);
|
|
164
|
-
return element;
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
168
|
-
this.null = function _null(node) {
|
|
169
|
-
const element = new _apidomCore.NullElement();
|
|
170
|
-
maybeAddSourceMap(node, element);
|
|
171
|
-
return element;
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
175
|
-
this.true = function _true(node) {
|
|
176
|
-
const element = new _apidomCore.BooleanElement(true);
|
|
177
|
-
maybeAddSourceMap(node, element);
|
|
178
|
-
return element;
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
182
|
-
this.false = function _false(node) {
|
|
183
|
-
const element = new _apidomCore.BooleanElement(false);
|
|
184
|
-
maybeAddSourceMap(node, element);
|
|
185
|
-
return element;
|
|
186
|
-
};
|
|
187
|
-
this.ERROR = function ERROR(node, key, parent, path) {
|
|
188
|
-
// collect errors as annotations
|
|
189
|
-
const isUnexpected = !node.hasError();
|
|
190
|
-
const value = node.text;
|
|
191
|
-
const message = isUnexpected ? `(Unexpected ${value})` : `(Error ${value})`;
|
|
192
|
-
const element = new _apidomCore.AnnotationElement(message);
|
|
193
|
-
element.classes.push('error');
|
|
194
|
-
maybeAddSourceMap(node, element);
|
|
195
|
-
if (path.length === 0) {
|
|
196
|
-
// no document to visit, only error is present in CST
|
|
197
|
-
const parseResultElement = new _apidomCore.ParseResultElement();
|
|
198
|
-
parseResultElement.push(element);
|
|
199
|
-
return parseResultElement;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// we have CST node for document
|
|
203
|
-
this.annotations.push(element);
|
|
204
|
-
return null;
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
32
|
|
|
209
33
|
/**
|
|
210
|
-
* This version of syntactic analysis translates TreeSitter CTS
|
|
34
|
+
* This version of syntactic analysis translates TreeSitter CTS
|
|
35
|
+
* directly into ApiDOM.
|
|
36
|
+
*
|
|
37
|
+
* Transient transformation of TreeSitter CST is performed
|
|
38
|
+
* using TreeSitter cursor. TreeSitter cursor is a stateful object
|
|
39
|
+
* that allows us to walk syntax tree containing large number of nodes
|
|
40
|
+
* with maximum efficiency. Using this transient CST transformation
|
|
41
|
+
* gives us double the performance when syntactically analyzing
|
|
42
|
+
* CST into ApiDOM.
|
|
43
|
+
*
|
|
211
44
|
* Single traversal pass is needed to get from CST to ApiDOM.
|
|
212
45
|
*/
|
|
213
46
|
const analyze = (cst, {
|
|
214
47
|
sourceMap = false
|
|
215
48
|
} = {}) => {
|
|
216
|
-
const visitor =
|
|
217
|
-
|
|
49
|
+
const visitor = (0, _CstVisitor.default)();
|
|
50
|
+
const cursor = cst.walk();
|
|
51
|
+
const iterator = new _TreeCursorIterator.default(cursor);
|
|
52
|
+
const rootNode = [...iterator].at(0);
|
|
53
|
+
return (0, _apidomAst.visit)(rootNode, visitor, {
|
|
218
54
|
// @ts-ignore
|
|
219
55
|
keyMap,
|
|
220
|
-
// @ts-ignore
|
|
221
56
|
nodeTypeGetter: getNodeType,
|
|
222
|
-
// @ts-ignore
|
|
223
57
|
nodePredicate: isNode,
|
|
224
58
|
state: {
|
|
225
59
|
sourceMap
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
|
|
4
|
+
exports.__esModule = true;
|
|
5
|
+
exports.default = void 0;
|
|
6
|
+
var _stampit = _interopRequireDefault(require("stampit"));
|
|
7
|
+
var _apidomCore = require("@swagger-api/apidom-core");
|
|
8
|
+
var _TreeCursorSyntaxNode = _interopRequireDefault(require("../../TreeCursorSyntaxNode.cjs"));
|
|
9
|
+
/* eslint-disable no-underscore-dangle */
|
|
10
|
+
|
|
11
|
+
const CstVisitor = (0, _stampit.default)({
|
|
12
|
+
props: {
|
|
13
|
+
sourceMap: false,
|
|
14
|
+
annotations: []
|
|
15
|
+
},
|
|
16
|
+
init() {
|
|
17
|
+
/**
|
|
18
|
+
* Private API.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
this.annotations = [];
|
|
22
|
+
const toPosition = node => {
|
|
23
|
+
const start = new _apidomCore.ArrayElement([node.startPosition.row, node.startPosition.column, node.startIndex]);
|
|
24
|
+
const end = new _apidomCore.ArrayElement([node.endPosition.row, node.endPosition.column, node.endIndex]);
|
|
25
|
+
start.classes.push('position');
|
|
26
|
+
end.classes.push('position');
|
|
27
|
+
return [start, end];
|
|
28
|
+
};
|
|
29
|
+
const maybeAddSourceMap = (node, element) => {
|
|
30
|
+
if (!this.sourceMap) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const sourceMap = new _apidomCore.SourceMapElement();
|
|
34
|
+
const position = toPosition(node);
|
|
35
|
+
if (position !== null) {
|
|
36
|
+
const [start, end] = position;
|
|
37
|
+
sourceMap.push(start);
|
|
38
|
+
sourceMap.push(end);
|
|
39
|
+
}
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
sourceMap.astNode = node;
|
|
42
|
+
element.meta.set('sourceMap', sourceMap);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Public API.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
this.enter = function enter(node) {
|
|
50
|
+
// missing anonymous literals from CST transformed into AnnotationElements.
|
|
51
|
+
if (node instanceof _TreeCursorSyntaxNode.default && !node.isNamed && node.isMissing) {
|
|
52
|
+
// collect annotations from missing literals
|
|
53
|
+
const value = node.type || node.text;
|
|
54
|
+
const message = `(Missing ${value})`;
|
|
55
|
+
const element = new _apidomCore.AnnotationElement(message);
|
|
56
|
+
element.classes.push('warning');
|
|
57
|
+
maybeAddSourceMap(node, element);
|
|
58
|
+
this.annotations.push(element);
|
|
59
|
+
}
|
|
60
|
+
return null; // remove everything unrecognized
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
this.document = function document(node) {
|
|
64
|
+
const element = new _apidomCore.ParseResultElement();
|
|
65
|
+
// @ts-ignore
|
|
66
|
+
element._content = node.children;
|
|
67
|
+
maybeAddSourceMap(node, element);
|
|
68
|
+
return element;
|
|
69
|
+
};
|
|
70
|
+
this.ParseResultElement = {
|
|
71
|
+
leave(element) {
|
|
72
|
+
// mark first-non Annotation element as result
|
|
73
|
+
// @ts-ignore
|
|
74
|
+
const elements = element.findElements(_apidomCore.isPrimitiveElement);
|
|
75
|
+
if (elements.length > 0) {
|
|
76
|
+
const resultElement = elements[0];
|
|
77
|
+
resultElement.classes.push('result');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// provide annotations
|
|
81
|
+
this.annotations.forEach(annotationElement => {
|
|
82
|
+
element.push(annotationElement);
|
|
83
|
+
});
|
|
84
|
+
this.annotations = [];
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
this.object = function object(node) {
|
|
88
|
+
const element = new _apidomCore.ObjectElement();
|
|
89
|
+
// @ts-ignore
|
|
90
|
+
element._content = node.children;
|
|
91
|
+
maybeAddSourceMap(node, element);
|
|
92
|
+
return element;
|
|
93
|
+
};
|
|
94
|
+
this.array = function array(node) {
|
|
95
|
+
const element = new _apidomCore.ArrayElement();
|
|
96
|
+
// @ts-ignore
|
|
97
|
+
element._content = node.children;
|
|
98
|
+
maybeAddSourceMap(node, element);
|
|
99
|
+
return element;
|
|
100
|
+
};
|
|
101
|
+
this.pair = function pair(node) {
|
|
102
|
+
const element = new _apidomCore.MemberElement();
|
|
103
|
+
// @ts-ignore
|
|
104
|
+
element.content.key = node.keyNode;
|
|
105
|
+
// @ts-ignore
|
|
106
|
+
element.content.value = node.valueNode;
|
|
107
|
+
maybeAddSourceMap(node, element);
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Process possible errors here that may be present in pair node children as we're using direct field access.
|
|
111
|
+
* There are usually 3 children here found: "key", ":", "value".
|
|
112
|
+
*/
|
|
113
|
+
if (node.children.length > 3) {
|
|
114
|
+
node.children.filter(child => child.type === 'ERROR').forEach(errorNode => {
|
|
115
|
+
this.ERROR(errorNode, node, [], [node]);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return element;
|
|
119
|
+
};
|
|
120
|
+
this.string = function string(node) {
|
|
121
|
+
const element = new _apidomCore.StringElement(JSON.parse(node.text));
|
|
122
|
+
maybeAddSourceMap(node, element);
|
|
123
|
+
return element;
|
|
124
|
+
};
|
|
125
|
+
this.number = function number(node) {
|
|
126
|
+
const element = new _apidomCore.NumberElement(Number(node.text));
|
|
127
|
+
maybeAddSourceMap(node, element);
|
|
128
|
+
return element;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
132
|
+
this.null = function _null(node) {
|
|
133
|
+
const element = new _apidomCore.NullElement();
|
|
134
|
+
maybeAddSourceMap(node, element);
|
|
135
|
+
return element;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
139
|
+
this.true = function _true(node) {
|
|
140
|
+
const element = new _apidomCore.BooleanElement(true);
|
|
141
|
+
maybeAddSourceMap(node, element);
|
|
142
|
+
return element;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
146
|
+
this.false = function _false(node) {
|
|
147
|
+
const element = new _apidomCore.BooleanElement(false);
|
|
148
|
+
maybeAddSourceMap(node, element);
|
|
149
|
+
return element;
|
|
150
|
+
};
|
|
151
|
+
this.ERROR = function ERROR(node, key, parent, path) {
|
|
152
|
+
// collect errors as annotations
|
|
153
|
+
const isUnexpected = !node.hasError;
|
|
154
|
+
const value = node.text;
|
|
155
|
+
const message = isUnexpected ? `(Unexpected ${value})` : `(Error ${value})`;
|
|
156
|
+
const element = new _apidomCore.AnnotationElement(message);
|
|
157
|
+
element.classes.push('error');
|
|
158
|
+
maybeAddSourceMap(node, element);
|
|
159
|
+
if (path.length === 0) {
|
|
160
|
+
// no document to visit, only error is present in CST
|
|
161
|
+
const parseResultElement = new _apidomCore.ParseResultElement();
|
|
162
|
+
parseResultElement.push(element);
|
|
163
|
+
return parseResultElement;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// we have CST node for document
|
|
167
|
+
this.annotations.push(element);
|
|
168
|
+
return null;
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
/* eslint-enable no-underscore-dangle */
|
|
174
|
+
var _default = CstVisitor;
|
|
175
|
+
exports.default = _default;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
|
|
3
4
|
exports.__esModule = true;
|
|
4
5
|
exports.default = void 0;
|
|
5
6
|
var _apidomAst = require("@swagger-api/apidom-ast");
|
|
7
|
+
var _TreeCursorIterator = _interopRequireDefault(require("../TreeCursorIterator.cjs"));
|
|
6
8
|
var _CstVisitor = _interopRequireWildcard(require("./visitors/CstVisitor.cjs"));
|
|
7
9
|
var _JsonAstVisitor = _interopRequireWildcard(require("./visitors/JsonAstVisitor.cjs"));
|
|
8
10
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
@@ -10,6 +12,14 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
|
|
|
10
12
|
/**
|
|
11
13
|
* This version of syntactic analysis does following transformations:
|
|
12
14
|
* TreeSitter CST -> JSON AST -> ApiDOM
|
|
15
|
+
*
|
|
16
|
+
* Transient transformation of TreeSitter CST is performed
|
|
17
|
+
* using TreeSitter cursor. TreeSitter cursor is a stateful object
|
|
18
|
+
* that allows us to walk syntax tree containing large number of nodes
|
|
19
|
+
* with maximum efficiency. Using this transient CST transformation
|
|
20
|
+
* gives us double the performance when syntactically analyzing
|
|
21
|
+
* CST into JSON AST.
|
|
22
|
+
*
|
|
13
23
|
* Two traversals passes are needed to get from CST to ApiDOM.
|
|
14
24
|
* This analysis is much slower than the direct one, but allows
|
|
15
25
|
* to do additional analysis magic on JSON AST.
|
|
@@ -17,9 +27,12 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
|
|
|
17
27
|
const analyze = (cst, {
|
|
18
28
|
sourceMap = false
|
|
19
29
|
} = {}) => {
|
|
30
|
+
const cursor = cst.walk();
|
|
31
|
+
const iterator = new _TreeCursorIterator.default(cursor);
|
|
32
|
+
const rootNode = [...iterator].at(0);
|
|
20
33
|
const cstVisitor = (0, _CstVisitor.default)();
|
|
21
34
|
const astVisitor = (0, _JsonAstVisitor.default)();
|
|
22
|
-
const jsonAst = (0, _apidomAst.visit)(
|
|
35
|
+
const jsonAst = (0, _apidomAst.visit)(rootNode, cstVisitor, {
|
|
23
36
|
// @ts-ignore
|
|
24
37
|
keyMap: _CstVisitor.keyMap,
|
|
25
38
|
state: {
|
|
@@ -29,7 +42,6 @@ const analyze = (cst, {
|
|
|
29
42
|
return (0, _apidomAst.visit)(jsonAst.rootNode, astVisitor, {
|
|
30
43
|
// @ts-ignore
|
|
31
44
|
keyMap: _JsonAstVisitor.keyMap,
|
|
32
|
-
// @ts-ignore
|
|
33
45
|
nodeTypeGetter: _JsonAstVisitor.getNodeType,
|
|
34
46
|
nodePredicate: _JsonAstVisitor.isNode,
|
|
35
47
|
state: {
|