@speclynx/apidom-parser-adapter-json 1.12.2 → 2.1.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 +24 -0
- package/NOTICE +16 -7
- package/README.md +36 -25
- package/dist/167.apidom-parser-adapter-json.browser.min.js +1 -1
- package/dist/451.apidom-parser-adapter-json.browser.min.js +1 -1
- package/dist/apidom-parser-adapter-json.browser.js +3101 -12890
- package/dist/apidom-parser-adapter-json.browser.min.js +1 -1
- package/package.json +7 -11
- package/src/adapter.cjs +29 -34
- package/src/adapter.mjs +26 -31
- package/src/native/index.cjs +30 -0
- package/src/native/index.mjs +25 -0
- package/src/tree-sitter/index.cjs +54 -0
- package/src/tree-sitter/index.mjs +48 -0
- package/src/{lexical-analysis → tree-sitter/lexical-analysis}/index.cjs +1 -1
- package/src/{lexical-analysis → tree-sitter/lexical-analysis}/index.mjs +1 -1
- package/src/tree-sitter/syntactic-analysis/index.cjs +223 -0
- package/src/tree-sitter/syntactic-analysis/index.mjs +219 -0
- package/types/apidom-parser-adapter-json.d.ts +14 -33
- package/src/syntactic-analysis/TreeCursorIterator.cjs +0 -62
- package/src/syntactic-analysis/TreeCursorIterator.mjs +0 -57
- package/src/syntactic-analysis/TreeCursorSyntaxNode.cjs +0 -51
- package/src/syntactic-analysis/TreeCursorSyntaxNode.mjs +0 -47
- package/src/syntactic-analysis/direct/index.cjs +0 -64
- package/src/syntactic-analysis/direct/index.mjs +0 -59
- package/src/syntactic-analysis/direct/visitors/CstVisitor.cjs +0 -163
- package/src/syntactic-analysis/direct/visitors/CstVisitor.mjs +0 -158
- package/src/syntactic-analysis/indirect/index.cjs +0 -56
- package/src/syntactic-analysis/indirect/index.mjs +0 -49
- package/src/syntactic-analysis/indirect/visitors/CstVisitor.cjs +0 -177
- package/src/syntactic-analysis/indirect/visitors/CstVisitor.mjs +0 -172
- package/src/syntactic-analysis/indirect/visitors/JsonAstVisitor.cjs +0 -189
- package/src/syntactic-analysis/indirect/visitors/JsonAstVisitor.mjs +0 -183
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.default = void 0;
|
|
5
|
+
var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
6
|
+
const getCursorInfo = cursor => ({
|
|
7
|
+
type: cursor.nodeType,
|
|
8
|
+
startPosition: cursor.startPosition,
|
|
9
|
+
endPosition: cursor.endPosition,
|
|
10
|
+
startIndex: cursor.startIndex,
|
|
11
|
+
endIndex: cursor.endIndex,
|
|
12
|
+
text: cursor.nodeText,
|
|
13
|
+
isNamed: cursor.nodeIsNamed,
|
|
14
|
+
isMissing: cursor.nodeIsMissing,
|
|
15
|
+
hasError: cursor.currentNode.hasError,
|
|
16
|
+
fieldName: cursor.currentFieldName
|
|
17
|
+
});
|
|
18
|
+
const maybeAddSourceMap = (info, element, ctx) => {
|
|
19
|
+
if (!ctx.sourceMap) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
element.startLine = info.startPosition.row;
|
|
23
|
+
element.startCharacter = info.startPosition.column;
|
|
24
|
+
element.startOffset = info.startIndex;
|
|
25
|
+
element.endLine = info.endPosition.row;
|
|
26
|
+
element.endCharacter = info.endPosition.column;
|
|
27
|
+
element.endOffset = info.endIndex;
|
|
28
|
+
};
|
|
29
|
+
const transform = (cursor, transformerMap, ctx) => {
|
|
30
|
+
const info = getCursorInfo(cursor);
|
|
31
|
+
|
|
32
|
+
// Handle missing anonymous literals
|
|
33
|
+
if (!info.isNamed && info.isMissing) {
|
|
34
|
+
const value = info.type || info.text;
|
|
35
|
+
const message = `(Missing ${value})`;
|
|
36
|
+
const element = new _apidomDatamodel.AnnotationElement(message);
|
|
37
|
+
element.classes.push('warning');
|
|
38
|
+
maybeAddSourceMap(info, element, ctx);
|
|
39
|
+
ctx.annotations.push(element);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const transformer = transformerMap[info.type];
|
|
43
|
+
if (!transformer) {
|
|
44
|
+
return null; // remove unrecognized nodes
|
|
45
|
+
}
|
|
46
|
+
return transformer(cursor, ctx);
|
|
47
|
+
};
|
|
48
|
+
const transformChildren = (cursor, transformerMap, ctx) => {
|
|
49
|
+
const results = [];
|
|
50
|
+
if (cursor.gotoFirstChild()) {
|
|
51
|
+
do {
|
|
52
|
+
const transformed = transform(cursor, transformerMap, ctx);
|
|
53
|
+
if (transformed !== null) {
|
|
54
|
+
results.push(transformed);
|
|
55
|
+
}
|
|
56
|
+
} while (cursor.gotoNextSibling());
|
|
57
|
+
cursor.gotoParent();
|
|
58
|
+
}
|
|
59
|
+
return results;
|
|
60
|
+
};
|
|
61
|
+
const createTransformers = transformerMap => ({
|
|
62
|
+
document(cursor, ctx) {
|
|
63
|
+
const info = getCursorInfo(cursor);
|
|
64
|
+
const element = new _apidomDatamodel.ParseResultElement();
|
|
65
|
+
maybeAddSourceMap(info, element, ctx);
|
|
66
|
+
|
|
67
|
+
// Transform children
|
|
68
|
+
const children = transformChildren(cursor, transformerMap, ctx);
|
|
69
|
+
for (const child of children) {
|
|
70
|
+
element.push(child);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Mark first non-Annotation element as result
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
const elements = element.findElements(_apidomDatamodel.isPrimitiveElement);
|
|
76
|
+
if (elements.length > 0) {
|
|
77
|
+
elements[0].classes.push('result');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Add collected annotations
|
|
81
|
+
for (const annotation of ctx.annotations) {
|
|
82
|
+
element.push(annotation);
|
|
83
|
+
}
|
|
84
|
+
ctx.annotations = [];
|
|
85
|
+
return element;
|
|
86
|
+
},
|
|
87
|
+
object(cursor, ctx) {
|
|
88
|
+
const info = getCursorInfo(cursor);
|
|
89
|
+
const element = new _apidomDatamodel.ObjectElement();
|
|
90
|
+
maybeAddSourceMap(info, element, ctx);
|
|
91
|
+
|
|
92
|
+
// Transform children (pairs)
|
|
93
|
+
const children = transformChildren(cursor, transformerMap, ctx);
|
|
94
|
+
for (const child of children) {
|
|
95
|
+
element.push(child);
|
|
96
|
+
}
|
|
97
|
+
return element;
|
|
98
|
+
},
|
|
99
|
+
array(cursor, ctx) {
|
|
100
|
+
const info = getCursorInfo(cursor);
|
|
101
|
+
const element = new _apidomDatamodel.ArrayElement();
|
|
102
|
+
maybeAddSourceMap(info, element, ctx);
|
|
103
|
+
|
|
104
|
+
// Transform children
|
|
105
|
+
const children = transformChildren(cursor, transformerMap, ctx);
|
|
106
|
+
for (const child of children) {
|
|
107
|
+
element.push(child);
|
|
108
|
+
}
|
|
109
|
+
return element;
|
|
110
|
+
},
|
|
111
|
+
pair(cursor, ctx) {
|
|
112
|
+
const info = getCursorInfo(cursor);
|
|
113
|
+
let key = null;
|
|
114
|
+
let value = null;
|
|
115
|
+
|
|
116
|
+
// Find key and value by field name
|
|
117
|
+
if (cursor.gotoFirstChild()) {
|
|
118
|
+
do {
|
|
119
|
+
const fieldName = cursor.currentFieldName;
|
|
120
|
+
if (fieldName === 'key') {
|
|
121
|
+
key = transform(cursor, transformerMap, ctx);
|
|
122
|
+
} else if (fieldName === 'value') {
|
|
123
|
+
value = transform(cursor, transformerMap, ctx);
|
|
124
|
+
} else if (cursor.nodeType === 'ERROR') {
|
|
125
|
+
// Process error nodes
|
|
126
|
+
transform(cursor, transformerMap, ctx);
|
|
127
|
+
}
|
|
128
|
+
} while (cursor.gotoNextSibling());
|
|
129
|
+
cursor.gotoParent();
|
|
130
|
+
}
|
|
131
|
+
const element = new _apidomDatamodel.MemberElement(key ?? new _apidomDatamodel.StringElement(''), value ?? new _apidomDatamodel.StringElement(''));
|
|
132
|
+
maybeAddSourceMap(info, element, ctx);
|
|
133
|
+
return element;
|
|
134
|
+
},
|
|
135
|
+
string(cursor, ctx) {
|
|
136
|
+
const info = getCursorInfo(cursor);
|
|
137
|
+
let element;
|
|
138
|
+
try {
|
|
139
|
+
element = new _apidomDatamodel.StringElement(JSON.parse(info.text));
|
|
140
|
+
} catch (error) {
|
|
141
|
+
element = new _apidomDatamodel.StringElement(info.text);
|
|
142
|
+
if (error instanceof Error) {
|
|
143
|
+
element.meta.set('jsonParse', {
|
|
144
|
+
isError: true,
|
|
145
|
+
errorType: error.name,
|
|
146
|
+
errorMessage: error.message
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
maybeAddSourceMap(info, element, ctx);
|
|
151
|
+
return element;
|
|
152
|
+
},
|
|
153
|
+
number(cursor, ctx) {
|
|
154
|
+
const info = getCursorInfo(cursor);
|
|
155
|
+
const element = new _apidomDatamodel.NumberElement(Number(info.text));
|
|
156
|
+
maybeAddSourceMap(info, element, ctx);
|
|
157
|
+
return element;
|
|
158
|
+
},
|
|
159
|
+
null(cursor, ctx) {
|
|
160
|
+
const info = getCursorInfo(cursor);
|
|
161
|
+
const element = new _apidomDatamodel.NullElement();
|
|
162
|
+
maybeAddSourceMap(info, element, ctx);
|
|
163
|
+
return element;
|
|
164
|
+
},
|
|
165
|
+
true(cursor, ctx) {
|
|
166
|
+
const info = getCursorInfo(cursor);
|
|
167
|
+
const element = new _apidomDatamodel.BooleanElement(true);
|
|
168
|
+
maybeAddSourceMap(info, element, ctx);
|
|
169
|
+
return element;
|
|
170
|
+
},
|
|
171
|
+
false(cursor, ctx) {
|
|
172
|
+
const info = getCursorInfo(cursor);
|
|
173
|
+
const element = new _apidomDatamodel.BooleanElement(false);
|
|
174
|
+
maybeAddSourceMap(info, element, ctx);
|
|
175
|
+
return element;
|
|
176
|
+
},
|
|
177
|
+
ERROR(cursor, ctx) {
|
|
178
|
+
const info = getCursorInfo(cursor);
|
|
179
|
+
const isUnexpected = !info.hasError;
|
|
180
|
+
const message = isUnexpected ? `(Unexpected ${info.text})` : `(Error ${info.text})`;
|
|
181
|
+
const element = new _apidomDatamodel.AnnotationElement(message);
|
|
182
|
+
element.classes.push('error');
|
|
183
|
+
maybeAddSourceMap(info, element, ctx);
|
|
184
|
+
ctx.annotations.push(element);
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Create the transformers map with self-reference for recursion
|
|
190
|
+
const transformers = {};
|
|
191
|
+
Object.assign(transformers, createTransformers(transformers));
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Syntactic analysis translates TreeSitter CST directly into ApiDOM.
|
|
195
|
+
*
|
|
196
|
+
* Direct transformation from TreeSitter CST using TreeSitter cursor.
|
|
197
|
+
* TreeSitter cursor is a stateful object that allows us to walk syntax tree
|
|
198
|
+
* containing large number of nodes with maximum efficiency.
|
|
199
|
+
*
|
|
200
|
+
* Single pass transformation from CST to ApiDOM.
|
|
201
|
+
* @public
|
|
202
|
+
*/
|
|
203
|
+
const analyze = (cst, {
|
|
204
|
+
sourceMap = false
|
|
205
|
+
} = {}) => {
|
|
206
|
+
const cursor = cst.walk();
|
|
207
|
+
const ctx = {
|
|
208
|
+
sourceMap,
|
|
209
|
+
annotations: []
|
|
210
|
+
};
|
|
211
|
+
const result = transform(cursor, transformers, ctx);
|
|
212
|
+
|
|
213
|
+
// Handle case where there's no document, only errors
|
|
214
|
+
if (result === null) {
|
|
215
|
+
const parseResult = new _apidomDatamodel.ParseResultElement();
|
|
216
|
+
for (const annotation of ctx.annotations) {
|
|
217
|
+
parseResult.push(annotation);
|
|
218
|
+
}
|
|
219
|
+
return parseResult;
|
|
220
|
+
}
|
|
221
|
+
return result;
|
|
222
|
+
};
|
|
223
|
+
var _default = exports.default = analyze;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { BooleanElement, NullElement, NumberElement, ParseResultElement, MemberElement, ObjectElement, ArrayElement, StringElement, AnnotationElement, isPrimitiveElement } from '@speclynx/apidom-datamodel';
|
|
2
|
+
const getCursorInfo = cursor => ({
|
|
3
|
+
type: cursor.nodeType,
|
|
4
|
+
startPosition: cursor.startPosition,
|
|
5
|
+
endPosition: cursor.endPosition,
|
|
6
|
+
startIndex: cursor.startIndex,
|
|
7
|
+
endIndex: cursor.endIndex,
|
|
8
|
+
text: cursor.nodeText,
|
|
9
|
+
isNamed: cursor.nodeIsNamed,
|
|
10
|
+
isMissing: cursor.nodeIsMissing,
|
|
11
|
+
hasError: cursor.currentNode.hasError,
|
|
12
|
+
fieldName: cursor.currentFieldName
|
|
13
|
+
});
|
|
14
|
+
const maybeAddSourceMap = (info, element, ctx) => {
|
|
15
|
+
if (!ctx.sourceMap) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
element.startLine = info.startPosition.row;
|
|
19
|
+
element.startCharacter = info.startPosition.column;
|
|
20
|
+
element.startOffset = info.startIndex;
|
|
21
|
+
element.endLine = info.endPosition.row;
|
|
22
|
+
element.endCharacter = info.endPosition.column;
|
|
23
|
+
element.endOffset = info.endIndex;
|
|
24
|
+
};
|
|
25
|
+
const transform = (cursor, transformerMap, ctx) => {
|
|
26
|
+
const info = getCursorInfo(cursor);
|
|
27
|
+
|
|
28
|
+
// Handle missing anonymous literals
|
|
29
|
+
if (!info.isNamed && info.isMissing) {
|
|
30
|
+
const value = info.type || info.text;
|
|
31
|
+
const message = `(Missing ${value})`;
|
|
32
|
+
const element = new AnnotationElement(message);
|
|
33
|
+
element.classes.push('warning');
|
|
34
|
+
maybeAddSourceMap(info, element, ctx);
|
|
35
|
+
ctx.annotations.push(element);
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const transformer = transformerMap[info.type];
|
|
39
|
+
if (!transformer) {
|
|
40
|
+
return null; // remove unrecognized nodes
|
|
41
|
+
}
|
|
42
|
+
return transformer(cursor, ctx);
|
|
43
|
+
};
|
|
44
|
+
const transformChildren = (cursor, transformerMap, ctx) => {
|
|
45
|
+
const results = [];
|
|
46
|
+
if (cursor.gotoFirstChild()) {
|
|
47
|
+
do {
|
|
48
|
+
const transformed = transform(cursor, transformerMap, ctx);
|
|
49
|
+
if (transformed !== null) {
|
|
50
|
+
results.push(transformed);
|
|
51
|
+
}
|
|
52
|
+
} while (cursor.gotoNextSibling());
|
|
53
|
+
cursor.gotoParent();
|
|
54
|
+
}
|
|
55
|
+
return results;
|
|
56
|
+
};
|
|
57
|
+
const createTransformers = transformerMap => ({
|
|
58
|
+
document(cursor, ctx) {
|
|
59
|
+
const info = getCursorInfo(cursor);
|
|
60
|
+
const element = new ParseResultElement();
|
|
61
|
+
maybeAddSourceMap(info, element, ctx);
|
|
62
|
+
|
|
63
|
+
// Transform children
|
|
64
|
+
const children = transformChildren(cursor, transformerMap, ctx);
|
|
65
|
+
for (const child of children) {
|
|
66
|
+
element.push(child);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Mark first non-Annotation element as result
|
|
70
|
+
// @ts-ignore
|
|
71
|
+
const elements = element.findElements(isPrimitiveElement);
|
|
72
|
+
if (elements.length > 0) {
|
|
73
|
+
elements[0].classes.push('result');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Add collected annotations
|
|
77
|
+
for (const annotation of ctx.annotations) {
|
|
78
|
+
element.push(annotation);
|
|
79
|
+
}
|
|
80
|
+
ctx.annotations = [];
|
|
81
|
+
return element;
|
|
82
|
+
},
|
|
83
|
+
object(cursor, ctx) {
|
|
84
|
+
const info = getCursorInfo(cursor);
|
|
85
|
+
const element = new ObjectElement();
|
|
86
|
+
maybeAddSourceMap(info, element, ctx);
|
|
87
|
+
|
|
88
|
+
// Transform children (pairs)
|
|
89
|
+
const children = transformChildren(cursor, transformerMap, ctx);
|
|
90
|
+
for (const child of children) {
|
|
91
|
+
element.push(child);
|
|
92
|
+
}
|
|
93
|
+
return element;
|
|
94
|
+
},
|
|
95
|
+
array(cursor, ctx) {
|
|
96
|
+
const info = getCursorInfo(cursor);
|
|
97
|
+
const element = new ArrayElement();
|
|
98
|
+
maybeAddSourceMap(info, element, ctx);
|
|
99
|
+
|
|
100
|
+
// Transform children
|
|
101
|
+
const children = transformChildren(cursor, transformerMap, ctx);
|
|
102
|
+
for (const child of children) {
|
|
103
|
+
element.push(child);
|
|
104
|
+
}
|
|
105
|
+
return element;
|
|
106
|
+
},
|
|
107
|
+
pair(cursor, ctx) {
|
|
108
|
+
const info = getCursorInfo(cursor);
|
|
109
|
+
let key = null;
|
|
110
|
+
let value = null;
|
|
111
|
+
|
|
112
|
+
// Find key and value by field name
|
|
113
|
+
if (cursor.gotoFirstChild()) {
|
|
114
|
+
do {
|
|
115
|
+
const fieldName = cursor.currentFieldName;
|
|
116
|
+
if (fieldName === 'key') {
|
|
117
|
+
key = transform(cursor, transformerMap, ctx);
|
|
118
|
+
} else if (fieldName === 'value') {
|
|
119
|
+
value = transform(cursor, transformerMap, ctx);
|
|
120
|
+
} else if (cursor.nodeType === 'ERROR') {
|
|
121
|
+
// Process error nodes
|
|
122
|
+
transform(cursor, transformerMap, ctx);
|
|
123
|
+
}
|
|
124
|
+
} while (cursor.gotoNextSibling());
|
|
125
|
+
cursor.gotoParent();
|
|
126
|
+
}
|
|
127
|
+
const element = new MemberElement(key ?? new StringElement(''), value ?? new StringElement(''));
|
|
128
|
+
maybeAddSourceMap(info, element, ctx);
|
|
129
|
+
return element;
|
|
130
|
+
},
|
|
131
|
+
string(cursor, ctx) {
|
|
132
|
+
const info = getCursorInfo(cursor);
|
|
133
|
+
let element;
|
|
134
|
+
try {
|
|
135
|
+
element = new StringElement(JSON.parse(info.text));
|
|
136
|
+
} catch (error) {
|
|
137
|
+
element = new StringElement(info.text);
|
|
138
|
+
if (error instanceof Error) {
|
|
139
|
+
element.meta.set('jsonParse', {
|
|
140
|
+
isError: true,
|
|
141
|
+
errorType: error.name,
|
|
142
|
+
errorMessage: error.message
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
maybeAddSourceMap(info, element, ctx);
|
|
147
|
+
return element;
|
|
148
|
+
},
|
|
149
|
+
number(cursor, ctx) {
|
|
150
|
+
const info = getCursorInfo(cursor);
|
|
151
|
+
const element = new NumberElement(Number(info.text));
|
|
152
|
+
maybeAddSourceMap(info, element, ctx);
|
|
153
|
+
return element;
|
|
154
|
+
},
|
|
155
|
+
null(cursor, ctx) {
|
|
156
|
+
const info = getCursorInfo(cursor);
|
|
157
|
+
const element = new NullElement();
|
|
158
|
+
maybeAddSourceMap(info, element, ctx);
|
|
159
|
+
return element;
|
|
160
|
+
},
|
|
161
|
+
true(cursor, ctx) {
|
|
162
|
+
const info = getCursorInfo(cursor);
|
|
163
|
+
const element = new BooleanElement(true);
|
|
164
|
+
maybeAddSourceMap(info, element, ctx);
|
|
165
|
+
return element;
|
|
166
|
+
},
|
|
167
|
+
false(cursor, ctx) {
|
|
168
|
+
const info = getCursorInfo(cursor);
|
|
169
|
+
const element = new BooleanElement(false);
|
|
170
|
+
maybeAddSourceMap(info, element, ctx);
|
|
171
|
+
return element;
|
|
172
|
+
},
|
|
173
|
+
ERROR(cursor, ctx) {
|
|
174
|
+
const info = getCursorInfo(cursor);
|
|
175
|
+
const isUnexpected = !info.hasError;
|
|
176
|
+
const message = isUnexpected ? `(Unexpected ${info.text})` : `(Error ${info.text})`;
|
|
177
|
+
const element = new AnnotationElement(message);
|
|
178
|
+
element.classes.push('error');
|
|
179
|
+
maybeAddSourceMap(info, element, ctx);
|
|
180
|
+
ctx.annotations.push(element);
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Create the transformers map with self-reference for recursion
|
|
186
|
+
const transformers = {};
|
|
187
|
+
Object.assign(transformers, createTransformers(transformers));
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Syntactic analysis translates TreeSitter CST directly into ApiDOM.
|
|
191
|
+
*
|
|
192
|
+
* Direct transformation from TreeSitter CST using TreeSitter cursor.
|
|
193
|
+
* TreeSitter cursor is a stateful object that allows us to walk syntax tree
|
|
194
|
+
* containing large number of nodes with maximum efficiency.
|
|
195
|
+
*
|
|
196
|
+
* Single pass transformation from CST to ApiDOM.
|
|
197
|
+
* @public
|
|
198
|
+
*/
|
|
199
|
+
const analyze = (cst, {
|
|
200
|
+
sourceMap = false
|
|
201
|
+
} = {}) => {
|
|
202
|
+
const cursor = cst.walk();
|
|
203
|
+
const ctx = {
|
|
204
|
+
sourceMap,
|
|
205
|
+
annotations: []
|
|
206
|
+
};
|
|
207
|
+
const result = transform(cursor, transformers, ctx);
|
|
208
|
+
|
|
209
|
+
// Handle case where there's no document, only errors
|
|
210
|
+
if (result === null) {
|
|
211
|
+
const parseResult = new ParseResultElement();
|
|
212
|
+
for (const annotation of ctx.annotations) {
|
|
213
|
+
parseResult.push(annotation);
|
|
214
|
+
}
|
|
215
|
+
return parseResult;
|
|
216
|
+
}
|
|
217
|
+
return result;
|
|
218
|
+
};
|
|
219
|
+
export default analyze;
|
|
@@ -1,37 +1,24 @@
|
|
|
1
1
|
import { MediaTypes } from '@speclynx/apidom-core';
|
|
2
|
-
import { Namespace } from '@speclynx/apidom-
|
|
3
|
-
import { ParseResultElement } from '@speclynx/apidom-
|
|
2
|
+
import { Namespace } from '@speclynx/apidom-datamodel';
|
|
3
|
+
import { ParseResultElement } from '@speclynx/apidom-datamodel';
|
|
4
4
|
import { Tree } from 'web-tree-sitter';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* This version of syntactic analysis translates TreeSitter CTS
|
|
8
|
-
* directly into ApiDOM.
|
|
9
|
-
*
|
|
10
|
-
* Transient transformation of TreeSitter CST is performed
|
|
11
|
-
* using TreeSitter cursor. TreeSitter cursor is a stateful object
|
|
12
|
-
* that allows us to walk syntax tree containing large number of nodes
|
|
13
|
-
* with maximum efficiency. Using this transient CST transformation
|
|
14
|
-
* gives us double the performance when syntactically analyzing
|
|
15
|
-
* CST into ApiDOM.
|
|
16
|
-
*
|
|
17
|
-
* Single traversal pass is needed to get from CST to ApiDOM.
|
|
18
7
|
* @public
|
|
19
8
|
*/
|
|
20
|
-
declare const
|
|
21
|
-
sourceMap?: boolean | undefined;
|
|
22
|
-
}) => ParseResultElement;
|
|
23
|
-
export { analyze as syntacticAnalysis }
|
|
24
|
-
export { analyze as syntacticAnalysisDirect }
|
|
9
|
+
export declare const detect: (source: string, { strict }?: DetectOptions) => Promise<boolean>;
|
|
25
10
|
|
|
26
11
|
/**
|
|
27
12
|
* @public
|
|
28
13
|
*/
|
|
29
|
-
export declare const
|
|
14
|
+
export declare const detectionRegExp: RegExp;
|
|
30
15
|
|
|
31
16
|
/**
|
|
32
17
|
* @public
|
|
33
18
|
*/
|
|
34
|
-
export declare
|
|
19
|
+
export declare interface DetectOptions {
|
|
20
|
+
strict?: boolean;
|
|
21
|
+
}
|
|
35
22
|
|
|
36
23
|
/**
|
|
37
24
|
* @public
|
|
@@ -75,26 +62,20 @@ export declare type ParseFunction = (source: string, options?: ParseFunctionOpti
|
|
|
75
62
|
*/
|
|
76
63
|
export declare interface ParseFunctionOptions {
|
|
77
64
|
sourceMap?: boolean;
|
|
78
|
-
|
|
65
|
+
strict?: boolean;
|
|
79
66
|
}
|
|
80
67
|
|
|
81
68
|
/**
|
|
82
|
-
*
|
|
83
|
-
* `TreeSitter CST -> JSON AST -> ApiDOM`
|
|
69
|
+
* Syntactic analysis translates TreeSitter CST directly into ApiDOM.
|
|
84
70
|
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* with maximum efficiency. Using this transient CST transformation
|
|
89
|
-
* gives us double the performance when syntactically analyzing
|
|
90
|
-
* CST into JSON AST.
|
|
71
|
+
* Direct transformation from TreeSitter CST using TreeSitter cursor.
|
|
72
|
+
* TreeSitter cursor is a stateful object that allows us to walk syntax tree
|
|
73
|
+
* containing large number of nodes with maximum efficiency.
|
|
91
74
|
*
|
|
92
|
-
*
|
|
93
|
-
* This analysis is much slower than the direct one, but allows
|
|
94
|
-
* to do additional analysis magic on JSON AST.
|
|
75
|
+
* Single pass transformation from CST to ApiDOM.
|
|
95
76
|
* @public
|
|
96
77
|
*/
|
|
97
|
-
export declare const
|
|
78
|
+
export declare const syntacticAnalysis: (cst: Tree, { sourceMap }?: {
|
|
98
79
|
sourceMap?: boolean | undefined;
|
|
99
80
|
}) => ParseResultElement;
|
|
100
81
|
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
4
|
-
exports.__esModule = true;
|
|
5
|
-
exports.default = void 0;
|
|
6
|
-
var _TreeCursorSyntaxNode = _interopRequireDefault(require("./TreeCursorSyntaxNode.cjs"));
|
|
7
|
-
class TreeCursorIterator {
|
|
8
|
-
cursor;
|
|
9
|
-
constructor(cursor) {
|
|
10
|
-
this.cursor = cursor;
|
|
11
|
-
}
|
|
12
|
-
document() {
|
|
13
|
-
return new _TreeCursorSyntaxNode.default(this.cursor);
|
|
14
|
-
}
|
|
15
|
-
object() {
|
|
16
|
-
return new _TreeCursorSyntaxNode.default(this.cursor).setFieldName(this.cursor);
|
|
17
|
-
}
|
|
18
|
-
array() {
|
|
19
|
-
return new _TreeCursorSyntaxNode.default(this.cursor).setFieldName(this.cursor);
|
|
20
|
-
}
|
|
21
|
-
pair() {
|
|
22
|
-
return new _TreeCursorSyntaxNode.default(this.cursor);
|
|
23
|
-
}
|
|
24
|
-
string() {
|
|
25
|
-
return new _TreeCursorSyntaxNode.default(this.cursor).setFieldName(this.cursor);
|
|
26
|
-
}
|
|
27
|
-
number() {
|
|
28
|
-
return new _TreeCursorSyntaxNode.default(this.cursor).setFieldName(this.cursor);
|
|
29
|
-
}
|
|
30
|
-
null() {
|
|
31
|
-
return new _TreeCursorSyntaxNode.default(this.cursor).setFieldName(this.cursor);
|
|
32
|
-
}
|
|
33
|
-
true() {
|
|
34
|
-
return new _TreeCursorSyntaxNode.default(this.cursor).setFieldName(this.cursor);
|
|
35
|
-
}
|
|
36
|
-
false() {
|
|
37
|
-
return new _TreeCursorSyntaxNode.default(this.cursor).setFieldName(this.cursor);
|
|
38
|
-
}
|
|
39
|
-
ERROR() {
|
|
40
|
-
return new _TreeCursorSyntaxNode.default(this.cursor).setHasError(this.cursor);
|
|
41
|
-
}
|
|
42
|
-
*[Symbol.iterator]() {
|
|
43
|
-
let node;
|
|
44
|
-
if (this.cursor.nodeType in this) {
|
|
45
|
-
// @ts-ignore
|
|
46
|
-
node = this[this.cursor.nodeType]();
|
|
47
|
-
} else {
|
|
48
|
-
node = new _TreeCursorSyntaxNode.default(this.cursor);
|
|
49
|
-
}
|
|
50
|
-
if (this.cursor.gotoFirstChild()) {
|
|
51
|
-
const [firstChild] = new TreeCursorIterator(this.cursor);
|
|
52
|
-
node.pushChildren(firstChild);
|
|
53
|
-
while (this.cursor.gotoNextSibling()) {
|
|
54
|
-
const firstChildSiblings = new TreeCursorIterator(this.cursor);
|
|
55
|
-
node.pushChildren(...firstChildSiblings);
|
|
56
|
-
}
|
|
57
|
-
this.cursor.gotoParent();
|
|
58
|
-
}
|
|
59
|
-
yield node;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
var _default = exports.default = TreeCursorIterator;
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import TreeCursorSyntaxNode from "./TreeCursorSyntaxNode.mjs";
|
|
2
|
-
class TreeCursorIterator {
|
|
3
|
-
cursor;
|
|
4
|
-
constructor(cursor) {
|
|
5
|
-
this.cursor = cursor;
|
|
6
|
-
}
|
|
7
|
-
document() {
|
|
8
|
-
return new TreeCursorSyntaxNode(this.cursor);
|
|
9
|
-
}
|
|
10
|
-
object() {
|
|
11
|
-
return new TreeCursorSyntaxNode(this.cursor).setFieldName(this.cursor);
|
|
12
|
-
}
|
|
13
|
-
array() {
|
|
14
|
-
return new TreeCursorSyntaxNode(this.cursor).setFieldName(this.cursor);
|
|
15
|
-
}
|
|
16
|
-
pair() {
|
|
17
|
-
return new TreeCursorSyntaxNode(this.cursor);
|
|
18
|
-
}
|
|
19
|
-
string() {
|
|
20
|
-
return new TreeCursorSyntaxNode(this.cursor).setFieldName(this.cursor);
|
|
21
|
-
}
|
|
22
|
-
number() {
|
|
23
|
-
return new TreeCursorSyntaxNode(this.cursor).setFieldName(this.cursor);
|
|
24
|
-
}
|
|
25
|
-
null() {
|
|
26
|
-
return new TreeCursorSyntaxNode(this.cursor).setFieldName(this.cursor);
|
|
27
|
-
}
|
|
28
|
-
true() {
|
|
29
|
-
return new TreeCursorSyntaxNode(this.cursor).setFieldName(this.cursor);
|
|
30
|
-
}
|
|
31
|
-
false() {
|
|
32
|
-
return new TreeCursorSyntaxNode(this.cursor).setFieldName(this.cursor);
|
|
33
|
-
}
|
|
34
|
-
ERROR() {
|
|
35
|
-
return new TreeCursorSyntaxNode(this.cursor).setHasError(this.cursor);
|
|
36
|
-
}
|
|
37
|
-
*[Symbol.iterator]() {
|
|
38
|
-
let node;
|
|
39
|
-
if (this.cursor.nodeType in this) {
|
|
40
|
-
// @ts-ignore
|
|
41
|
-
node = this[this.cursor.nodeType]();
|
|
42
|
-
} else {
|
|
43
|
-
node = new TreeCursorSyntaxNode(this.cursor);
|
|
44
|
-
}
|
|
45
|
-
if (this.cursor.gotoFirstChild()) {
|
|
46
|
-
const [firstChild] = new TreeCursorIterator(this.cursor);
|
|
47
|
-
node.pushChildren(firstChild);
|
|
48
|
-
while (this.cursor.gotoNextSibling()) {
|
|
49
|
-
const firstChildSiblings = new TreeCursorIterator(this.cursor);
|
|
50
|
-
node.pushChildren(...firstChildSiblings);
|
|
51
|
-
}
|
|
52
|
-
this.cursor.gotoParent();
|
|
53
|
-
}
|
|
54
|
-
yield node;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
export default TreeCursorIterator;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
exports.__esModule = true;
|
|
4
|
-
exports.default = void 0;
|
|
5
|
-
class TreeCursorSyntaxNode {
|
|
6
|
-
type;
|
|
7
|
-
startPosition;
|
|
8
|
-
endPosition;
|
|
9
|
-
startIndex;
|
|
10
|
-
endIndex;
|
|
11
|
-
text;
|
|
12
|
-
isNamed;
|
|
13
|
-
isMissing;
|
|
14
|
-
fieldName = null;
|
|
15
|
-
hasError = false;
|
|
16
|
-
children = [];
|
|
17
|
-
constructor(cursor) {
|
|
18
|
-
this.type = cursor.nodeType;
|
|
19
|
-
this.startPosition = cursor.startPosition;
|
|
20
|
-
this.endPosition = cursor.endPosition;
|
|
21
|
-
this.startIndex = cursor.startIndex;
|
|
22
|
-
this.endIndex = cursor.endIndex;
|
|
23
|
-
this.text = cursor.nodeText;
|
|
24
|
-
this.isNamed = cursor.nodeIsNamed;
|
|
25
|
-
this.isMissing = cursor.nodeIsMissing;
|
|
26
|
-
}
|
|
27
|
-
get keyNode() {
|
|
28
|
-
if (this.type === 'pair') {
|
|
29
|
-
return this.children.find(node => node.fieldName === 'key');
|
|
30
|
-
}
|
|
31
|
-
return undefined;
|
|
32
|
-
}
|
|
33
|
-
get valueNode() {
|
|
34
|
-
if (this.type === 'pair') {
|
|
35
|
-
return this.children.find(node => node.fieldName === 'value');
|
|
36
|
-
}
|
|
37
|
-
return undefined;
|
|
38
|
-
}
|
|
39
|
-
setFieldName(cursor) {
|
|
40
|
-
this.fieldName = cursor.currentFieldName;
|
|
41
|
-
return this;
|
|
42
|
-
}
|
|
43
|
-
setHasError(cursor) {
|
|
44
|
-
this.hasError = cursor.currentNode.hasError;
|
|
45
|
-
return this;
|
|
46
|
-
}
|
|
47
|
-
pushChildren(...children) {
|
|
48
|
-
this.children.push(...children);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
var _default = exports.default = TreeCursorSyntaxNode;
|