@speclynx/apidom-parser-adapter-json 1.12.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 +91 -0
- package/LICENSE +202 -0
- package/LICENSES/AFL-3.0.txt +182 -0
- package/LICENSES/Apache-2.0.txt +202 -0
- package/LICENSES/BSD-3-Clause.txt +26 -0
- package/LICENSES/MIT.txt +9 -0
- package/NOTICE +65 -0
- package/README.md +124 -0
- package/dist/167.apidom-parser-adapter-json.browser.js +10 -0
- package/dist/167.apidom-parser-adapter-json.browser.min.js +1 -0
- package/dist/451.apidom-parser-adapter-json.browser.js +10 -0
- package/dist/451.apidom-parser-adapter-json.browser.min.js +1 -0
- package/dist/9786785aaddf11f37840.wasm +0 -0
- package/dist/apidom-parser-adapter-json.browser.js +17850 -0
- package/dist/apidom-parser-adapter-json.browser.min.js +1 -0
- package/package.json +69 -0
- package/src/adapter.cjs +75 -0
- package/src/adapter.mjs +65 -0
- package/src/lexical-analysis/index.cjs +42 -0
- package/src/lexical-analysis/index.mjs +38 -0
- package/src/media-types.cjs +20 -0
- package/src/media-types.mjs +16 -0
- package/src/syntactic-analysis/TreeCursorIterator.cjs +62 -0
- package/src/syntactic-analysis/TreeCursorIterator.mjs +57 -0
- package/src/syntactic-analysis/TreeCursorSyntaxNode.cjs +51 -0
- package/src/syntactic-analysis/TreeCursorSyntaxNode.mjs +47 -0
- package/src/syntactic-analysis/direct/index.cjs +64 -0
- package/src/syntactic-analysis/direct/index.mjs +59 -0
- package/src/syntactic-analysis/direct/visitors/CstVisitor.cjs +163 -0
- package/src/syntactic-analysis/direct/visitors/CstVisitor.mjs +158 -0
- package/src/syntactic-analysis/indirect/index.cjs +56 -0
- package/src/syntactic-analysis/indirect/index.mjs +49 -0
- package/src/syntactic-analysis/indirect/visitors/CstVisitor.cjs +177 -0
- package/src/syntactic-analysis/indirect/visitors/CstVisitor.mjs +172 -0
- package/src/syntactic-analysis/indirect/visitors/JsonAstVisitor.cjs +189 -0
- package/src/syntactic-analysis/indirect/visitors/JsonAstVisitor.mjs +183 -0
- package/types/apidom-parser-adapter-json.d.ts +103 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.default = exports.JSONMediaTypes = void 0;
|
|
5
|
+
var _apidomCore = require("@speclynx/apidom-core");
|
|
6
|
+
/**
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
class JSONMediaTypes extends _apidomCore.MediaTypes {
|
|
10
|
+
latest() {
|
|
11
|
+
return this[0];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
exports.JSONMediaTypes = JSONMediaTypes;
|
|
19
|
+
const mediaTypes = new JSONMediaTypes('application/json');
|
|
20
|
+
var _default = exports.default = mediaTypes;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { MediaTypes } from '@speclynx/apidom-core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export class JSONMediaTypes extends MediaTypes {
|
|
7
|
+
latest() {
|
|
8
|
+
return this[0];
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
const mediaTypes = new JSONMediaTypes('application/json');
|
|
16
|
+
export default mediaTypes;
|
|
@@ -0,0 +1,62 @@
|
|
|
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;
|
|
@@ -0,0 +1,57 @@
|
|
|
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;
|
|
@@ -0,0 +1,51 @@
|
|
|
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;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
class TreeCursorSyntaxNode {
|
|
2
|
+
type;
|
|
3
|
+
startPosition;
|
|
4
|
+
endPosition;
|
|
5
|
+
startIndex;
|
|
6
|
+
endIndex;
|
|
7
|
+
text;
|
|
8
|
+
isNamed;
|
|
9
|
+
isMissing;
|
|
10
|
+
fieldName = null;
|
|
11
|
+
hasError = false;
|
|
12
|
+
children = [];
|
|
13
|
+
constructor(cursor) {
|
|
14
|
+
this.type = cursor.nodeType;
|
|
15
|
+
this.startPosition = cursor.startPosition;
|
|
16
|
+
this.endPosition = cursor.endPosition;
|
|
17
|
+
this.startIndex = cursor.startIndex;
|
|
18
|
+
this.endIndex = cursor.endIndex;
|
|
19
|
+
this.text = cursor.nodeText;
|
|
20
|
+
this.isNamed = cursor.nodeIsNamed;
|
|
21
|
+
this.isMissing = cursor.nodeIsMissing;
|
|
22
|
+
}
|
|
23
|
+
get keyNode() {
|
|
24
|
+
if (this.type === 'pair') {
|
|
25
|
+
return this.children.find(node => node.fieldName === 'key');
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
get valueNode() {
|
|
30
|
+
if (this.type === 'pair') {
|
|
31
|
+
return this.children.find(node => node.fieldName === 'value');
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
setFieldName(cursor) {
|
|
36
|
+
this.fieldName = cursor.currentFieldName;
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
setHasError(cursor) {
|
|
40
|
+
this.hasError = cursor.currentNode.hasError;
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
pushChildren(...children) {
|
|
44
|
+
this.children.push(...children);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export default TreeCursorSyntaxNode;
|
|
@@ -0,0 +1,64 @@
|
|
|
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 _apidomAst = require("@speclynx/apidom-ast");
|
|
7
|
+
var _apidomCore = require("@speclynx/apidom-core");
|
|
8
|
+
var _CstVisitor = _interopRequireDefault(require("./visitors/CstVisitor.cjs"));
|
|
9
|
+
var _TreeCursorIterator = _interopRequireDefault(require("../TreeCursorIterator.cjs"));
|
|
10
|
+
const keyMap = {
|
|
11
|
+
document: ['children'],
|
|
12
|
+
object: ['children'],
|
|
13
|
+
array: ['children'],
|
|
14
|
+
string: ['children'],
|
|
15
|
+
property: ['children'],
|
|
16
|
+
key: ['children'],
|
|
17
|
+
error: ['children'],
|
|
18
|
+
..._apidomCore.keyMap
|
|
19
|
+
};
|
|
20
|
+
const getNodeType = node => {
|
|
21
|
+
if ((0, _apidomCore.isParseResultElement)(node)) {
|
|
22
|
+
return 'ParseResultElement';
|
|
23
|
+
}
|
|
24
|
+
if ((0, _apidomCore.isElement)(node)) {
|
|
25
|
+
return (0, _apidomCore.getNodeType)(node);
|
|
26
|
+
}
|
|
27
|
+
return (0, _apidomAst.getNodeType)(node);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// @ts-ignore
|
|
31
|
+
const isNode = element => (0, _apidomCore.isElement)(element) || (0, _apidomAst.isNode)(element);
|
|
32
|
+
|
|
33
|
+
/**
|
|
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
|
+
*
|
|
44
|
+
* Single traversal pass is needed to get from CST to ApiDOM.
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
const analyze = (cst, {
|
|
48
|
+
sourceMap = false
|
|
49
|
+
} = {}) => {
|
|
50
|
+
const visitor = new _CstVisitor.default();
|
|
51
|
+
const cursor = cst.walk();
|
|
52
|
+
const iterator = new _TreeCursorIterator.default(cursor);
|
|
53
|
+
const [rootNode] = Array.from(iterator);
|
|
54
|
+
return (0, _apidomAst.visit)(rootNode, visitor, {
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
keyMap,
|
|
57
|
+
nodeTypeGetter: getNodeType,
|
|
58
|
+
nodePredicate: isNode,
|
|
59
|
+
state: {
|
|
60
|
+
sourceMap
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
var _default = exports.default = analyze;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { visit, getNodeType as getCSTNodeType, isNode as isCSTNode } from '@speclynx/apidom-ast';
|
|
2
|
+
import { isElement, isParseResultElement, keyMap as keyMapApiDOM, getNodeType as getNodeTypeApiDOM } from '@speclynx/apidom-core';
|
|
3
|
+
import CstVisitor from "./visitors/CstVisitor.mjs";
|
|
4
|
+
import TreeCursorIterator from "../TreeCursorIterator.mjs";
|
|
5
|
+
const keyMap = {
|
|
6
|
+
document: ['children'],
|
|
7
|
+
object: ['children'],
|
|
8
|
+
array: ['children'],
|
|
9
|
+
string: ['children'],
|
|
10
|
+
property: ['children'],
|
|
11
|
+
key: ['children'],
|
|
12
|
+
error: ['children'],
|
|
13
|
+
...keyMapApiDOM
|
|
14
|
+
};
|
|
15
|
+
const getNodeType = node => {
|
|
16
|
+
if (isParseResultElement(node)) {
|
|
17
|
+
return 'ParseResultElement';
|
|
18
|
+
}
|
|
19
|
+
if (isElement(node)) {
|
|
20
|
+
return getNodeTypeApiDOM(node);
|
|
21
|
+
}
|
|
22
|
+
return getCSTNodeType(node);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
const isNode = element => isElement(element) || isCSTNode(element);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* This version of syntactic analysis translates TreeSitter CTS
|
|
30
|
+
* directly into ApiDOM.
|
|
31
|
+
*
|
|
32
|
+
* Transient transformation of TreeSitter CST is performed
|
|
33
|
+
* using TreeSitter cursor. TreeSitter cursor is a stateful object
|
|
34
|
+
* that allows us to walk syntax tree containing large number of nodes
|
|
35
|
+
* with maximum efficiency. Using this transient CST transformation
|
|
36
|
+
* gives us double the performance when syntactically analyzing
|
|
37
|
+
* CST into ApiDOM.
|
|
38
|
+
*
|
|
39
|
+
* Single traversal pass is needed to get from CST to ApiDOM.
|
|
40
|
+
* @public
|
|
41
|
+
*/
|
|
42
|
+
const analyze = (cst, {
|
|
43
|
+
sourceMap = false
|
|
44
|
+
} = {}) => {
|
|
45
|
+
const visitor = new CstVisitor();
|
|
46
|
+
const cursor = cst.walk();
|
|
47
|
+
const iterator = new TreeCursorIterator(cursor);
|
|
48
|
+
const [rootNode] = Array.from(iterator);
|
|
49
|
+
return visit(rootNode, visitor, {
|
|
50
|
+
// @ts-ignore
|
|
51
|
+
keyMap,
|
|
52
|
+
nodeTypeGetter: getNodeType,
|
|
53
|
+
nodePredicate: isNode,
|
|
54
|
+
state: {
|
|
55
|
+
sourceMap
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
export default analyze;
|
|
@@ -0,0 +1,163 @@
|
|
|
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 _apidomCore = require("@speclynx/apidom-core");
|
|
7
|
+
var _TreeCursorSyntaxNode = _interopRequireDefault(require("../../TreeCursorSyntaxNode.cjs"));
|
|
8
|
+
class CstVisitor {
|
|
9
|
+
static toPosition(node) {
|
|
10
|
+
const start = new _apidomCore.ArrayElement([node.startPosition.row, node.startPosition.column, node.startIndex]);
|
|
11
|
+
const end = new _apidomCore.ArrayElement([node.endPosition.row, node.endPosition.column, node.endIndex]);
|
|
12
|
+
start.classes.push('position');
|
|
13
|
+
end.classes.push('position');
|
|
14
|
+
return [start, end];
|
|
15
|
+
}
|
|
16
|
+
sourceMap = false;
|
|
17
|
+
annotations;
|
|
18
|
+
ParseResultElement = {
|
|
19
|
+
leave: element => {
|
|
20
|
+
// mark first-non Annotation element as result
|
|
21
|
+
// @ts-ignore
|
|
22
|
+
const elements = element.findElements(_apidomCore.isPrimitiveElement);
|
|
23
|
+
if (elements.length > 0) {
|
|
24
|
+
const resultElement = elements[0];
|
|
25
|
+
resultElement.classes.push('result');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// provide annotations
|
|
29
|
+
this.annotations.forEach(annotationElement => {
|
|
30
|
+
element.push(annotationElement);
|
|
31
|
+
});
|
|
32
|
+
this.annotations = [];
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
constructor() {
|
|
36
|
+
this.annotations = [];
|
|
37
|
+
}
|
|
38
|
+
enter(node) {
|
|
39
|
+
// missing anonymous literals from CST transformed into AnnotationElements.
|
|
40
|
+
if (node instanceof _TreeCursorSyntaxNode.default && !node.isNamed && node.isMissing) {
|
|
41
|
+
// collect annotations from missing literals
|
|
42
|
+
const value = node.type || node.text;
|
|
43
|
+
const message = `(Missing ${value})`;
|
|
44
|
+
const element = new _apidomCore.AnnotationElement(message);
|
|
45
|
+
element.classes.push('warning');
|
|
46
|
+
this.maybeAddSourceMap(node, element);
|
|
47
|
+
this.annotations.push(element);
|
|
48
|
+
}
|
|
49
|
+
return null; // remove everything unrecognized
|
|
50
|
+
}
|
|
51
|
+
document(node) {
|
|
52
|
+
const element = new _apidomCore.ParseResultElement();
|
|
53
|
+
// @ts-ignore
|
|
54
|
+
element._content = node.children;
|
|
55
|
+
this.maybeAddSourceMap(node, element);
|
|
56
|
+
return element;
|
|
57
|
+
}
|
|
58
|
+
object(node) {
|
|
59
|
+
const element = new _apidomCore.ObjectElement();
|
|
60
|
+
// @ts-ignore
|
|
61
|
+
element._content = node.children;
|
|
62
|
+
this.maybeAddSourceMap(node, element);
|
|
63
|
+
return element;
|
|
64
|
+
}
|
|
65
|
+
array(node) {
|
|
66
|
+
const element = new _apidomCore.ArrayElement();
|
|
67
|
+
// @ts-ignore
|
|
68
|
+
element._content = node.children;
|
|
69
|
+
this.maybeAddSourceMap(node, element);
|
|
70
|
+
return element;
|
|
71
|
+
}
|
|
72
|
+
pair(node) {
|
|
73
|
+
const element = new _apidomCore.MemberElement();
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
element.content.key = node.keyNode;
|
|
76
|
+
// @ts-ignore
|
|
77
|
+
element.content.value = node.valueNode;
|
|
78
|
+
this.maybeAddSourceMap(node, element);
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Process possible errors here that may be present in pair node children as we're using direct field access.
|
|
82
|
+
* There are usually 3 children here found: "key", ":", "value".
|
|
83
|
+
*/
|
|
84
|
+
if (node.children.length > 3) {
|
|
85
|
+
node.children.filter(child => child.type === 'ERROR').forEach(errorNode => {
|
|
86
|
+
this.ERROR(errorNode, node, [], [node]);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return element;
|
|
90
|
+
}
|
|
91
|
+
string(node) {
|
|
92
|
+
let element;
|
|
93
|
+
try {
|
|
94
|
+
element = new _apidomCore.StringElement(JSON.parse(node.text));
|
|
95
|
+
} catch (error) {
|
|
96
|
+
element = new _apidomCore.StringElement(node.text);
|
|
97
|
+
if (error instanceof Error) {
|
|
98
|
+
element.setMetaProperty('jsonParse', {
|
|
99
|
+
isError: true,
|
|
100
|
+
errorType: error.name,
|
|
101
|
+
errorMessage: error.message
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
this.maybeAddSourceMap(node, element);
|
|
106
|
+
return element;
|
|
107
|
+
}
|
|
108
|
+
number(node) {
|
|
109
|
+
const element = new _apidomCore.NumberElement(Number(node.text));
|
|
110
|
+
this.maybeAddSourceMap(node, element);
|
|
111
|
+
return element;
|
|
112
|
+
}
|
|
113
|
+
null(node) {
|
|
114
|
+
const element = new _apidomCore.NullElement();
|
|
115
|
+
this.maybeAddSourceMap(node, element);
|
|
116
|
+
return element;
|
|
117
|
+
}
|
|
118
|
+
true(node) {
|
|
119
|
+
const element = new _apidomCore.BooleanElement(true);
|
|
120
|
+
this.maybeAddSourceMap(node, element);
|
|
121
|
+
return element;
|
|
122
|
+
}
|
|
123
|
+
false(node) {
|
|
124
|
+
const element = new _apidomCore.BooleanElement(false);
|
|
125
|
+
this.maybeAddSourceMap(node, element);
|
|
126
|
+
return element;
|
|
127
|
+
}
|
|
128
|
+
ERROR(node, key, parent, path) {
|
|
129
|
+
// collect errors as annotations
|
|
130
|
+
const isUnexpected = !node.hasError;
|
|
131
|
+
const value = node.text;
|
|
132
|
+
const message = isUnexpected ? `(Unexpected ${value})` : `(Error ${value})`;
|
|
133
|
+
const element = new _apidomCore.AnnotationElement(message);
|
|
134
|
+
element.classes.push('error');
|
|
135
|
+
this.maybeAddSourceMap(node, element);
|
|
136
|
+
if (path.length === 0) {
|
|
137
|
+
// no document to visit, only error is present in CST
|
|
138
|
+
const parseResultElement = new _apidomCore.ParseResultElement();
|
|
139
|
+
parseResultElement.push(element);
|
|
140
|
+
return parseResultElement;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// we have CST node for document
|
|
144
|
+
this.annotations.push(element);
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
maybeAddSourceMap(node, element) {
|
|
148
|
+
if (!this.sourceMap) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const sourceMap = new _apidomCore.SourceMapElement();
|
|
152
|
+
const position = CstVisitor.toPosition(node);
|
|
153
|
+
if (position !== null) {
|
|
154
|
+
const [start, end] = position;
|
|
155
|
+
sourceMap.push(start);
|
|
156
|
+
sourceMap.push(end);
|
|
157
|
+
}
|
|
158
|
+
// @ts-ignore
|
|
159
|
+
sourceMap.astNode = node;
|
|
160
|
+
element.meta.set('sourceMap', sourceMap);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
var _default = exports.default = CstVisitor;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { BooleanElement, NullElement, NumberElement, ParseResultElement, SourceMapElement, MemberElement, ObjectElement, ArrayElement, StringElement, AnnotationElement, isPrimitiveElement } from '@speclynx/apidom-core';
|
|
2
|
+
import TreeCursorSyntaxNode from "../../TreeCursorSyntaxNode.mjs";
|
|
3
|
+
class CstVisitor {
|
|
4
|
+
static toPosition(node) {
|
|
5
|
+
const start = new ArrayElement([node.startPosition.row, node.startPosition.column, node.startIndex]);
|
|
6
|
+
const end = new ArrayElement([node.endPosition.row, node.endPosition.column, node.endIndex]);
|
|
7
|
+
start.classes.push('position');
|
|
8
|
+
end.classes.push('position');
|
|
9
|
+
return [start, end];
|
|
10
|
+
}
|
|
11
|
+
sourceMap = false;
|
|
12
|
+
annotations;
|
|
13
|
+
ParseResultElement = {
|
|
14
|
+
leave: element => {
|
|
15
|
+
// mark first-non Annotation element as result
|
|
16
|
+
// @ts-ignore
|
|
17
|
+
const elements = element.findElements(isPrimitiveElement);
|
|
18
|
+
if (elements.length > 0) {
|
|
19
|
+
const resultElement = elements[0];
|
|
20
|
+
resultElement.classes.push('result');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// provide annotations
|
|
24
|
+
this.annotations.forEach(annotationElement => {
|
|
25
|
+
element.push(annotationElement);
|
|
26
|
+
});
|
|
27
|
+
this.annotations = [];
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
constructor() {
|
|
31
|
+
this.annotations = [];
|
|
32
|
+
}
|
|
33
|
+
enter(node) {
|
|
34
|
+
// missing anonymous literals from CST transformed into AnnotationElements.
|
|
35
|
+
if (node instanceof TreeCursorSyntaxNode && !node.isNamed && node.isMissing) {
|
|
36
|
+
// collect annotations from missing literals
|
|
37
|
+
const value = node.type || node.text;
|
|
38
|
+
const message = `(Missing ${value})`;
|
|
39
|
+
const element = new AnnotationElement(message);
|
|
40
|
+
element.classes.push('warning');
|
|
41
|
+
this.maybeAddSourceMap(node, element);
|
|
42
|
+
this.annotations.push(element);
|
|
43
|
+
}
|
|
44
|
+
return null; // remove everything unrecognized
|
|
45
|
+
}
|
|
46
|
+
document(node) {
|
|
47
|
+
const element = new ParseResultElement();
|
|
48
|
+
// @ts-ignore
|
|
49
|
+
element._content = node.children;
|
|
50
|
+
this.maybeAddSourceMap(node, element);
|
|
51
|
+
return element;
|
|
52
|
+
}
|
|
53
|
+
object(node) {
|
|
54
|
+
const element = new ObjectElement();
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
element._content = node.children;
|
|
57
|
+
this.maybeAddSourceMap(node, element);
|
|
58
|
+
return element;
|
|
59
|
+
}
|
|
60
|
+
array(node) {
|
|
61
|
+
const element = new ArrayElement();
|
|
62
|
+
// @ts-ignore
|
|
63
|
+
element._content = node.children;
|
|
64
|
+
this.maybeAddSourceMap(node, element);
|
|
65
|
+
return element;
|
|
66
|
+
}
|
|
67
|
+
pair(node) {
|
|
68
|
+
const element = new MemberElement();
|
|
69
|
+
// @ts-ignore
|
|
70
|
+
element.content.key = node.keyNode;
|
|
71
|
+
// @ts-ignore
|
|
72
|
+
element.content.value = node.valueNode;
|
|
73
|
+
this.maybeAddSourceMap(node, element);
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Process possible errors here that may be present in pair node children as we're using direct field access.
|
|
77
|
+
* There are usually 3 children here found: "key", ":", "value".
|
|
78
|
+
*/
|
|
79
|
+
if (node.children.length > 3) {
|
|
80
|
+
node.children.filter(child => child.type === 'ERROR').forEach(errorNode => {
|
|
81
|
+
this.ERROR(errorNode, node, [], [node]);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return element;
|
|
85
|
+
}
|
|
86
|
+
string(node) {
|
|
87
|
+
let element;
|
|
88
|
+
try {
|
|
89
|
+
element = new StringElement(JSON.parse(node.text));
|
|
90
|
+
} catch (error) {
|
|
91
|
+
element = new StringElement(node.text);
|
|
92
|
+
if (error instanceof Error) {
|
|
93
|
+
element.setMetaProperty('jsonParse', {
|
|
94
|
+
isError: true,
|
|
95
|
+
errorType: error.name,
|
|
96
|
+
errorMessage: error.message
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
this.maybeAddSourceMap(node, element);
|
|
101
|
+
return element;
|
|
102
|
+
}
|
|
103
|
+
number(node) {
|
|
104
|
+
const element = new NumberElement(Number(node.text));
|
|
105
|
+
this.maybeAddSourceMap(node, element);
|
|
106
|
+
return element;
|
|
107
|
+
}
|
|
108
|
+
null(node) {
|
|
109
|
+
const element = new NullElement();
|
|
110
|
+
this.maybeAddSourceMap(node, element);
|
|
111
|
+
return element;
|
|
112
|
+
}
|
|
113
|
+
true(node) {
|
|
114
|
+
const element = new BooleanElement(true);
|
|
115
|
+
this.maybeAddSourceMap(node, element);
|
|
116
|
+
return element;
|
|
117
|
+
}
|
|
118
|
+
false(node) {
|
|
119
|
+
const element = new BooleanElement(false);
|
|
120
|
+
this.maybeAddSourceMap(node, element);
|
|
121
|
+
return element;
|
|
122
|
+
}
|
|
123
|
+
ERROR(node, key, parent, path) {
|
|
124
|
+
// collect errors as annotations
|
|
125
|
+
const isUnexpected = !node.hasError;
|
|
126
|
+
const value = node.text;
|
|
127
|
+
const message = isUnexpected ? `(Unexpected ${value})` : `(Error ${value})`;
|
|
128
|
+
const element = new AnnotationElement(message);
|
|
129
|
+
element.classes.push('error');
|
|
130
|
+
this.maybeAddSourceMap(node, element);
|
|
131
|
+
if (path.length === 0) {
|
|
132
|
+
// no document to visit, only error is present in CST
|
|
133
|
+
const parseResultElement = new ParseResultElement();
|
|
134
|
+
parseResultElement.push(element);
|
|
135
|
+
return parseResultElement;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// we have CST node for document
|
|
139
|
+
this.annotations.push(element);
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
maybeAddSourceMap(node, element) {
|
|
143
|
+
if (!this.sourceMap) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const sourceMap = new SourceMapElement();
|
|
147
|
+
const position = CstVisitor.toPosition(node);
|
|
148
|
+
if (position !== null) {
|
|
149
|
+
const [start, end] = position;
|
|
150
|
+
sourceMap.push(start);
|
|
151
|
+
sourceMap.push(end);
|
|
152
|
+
}
|
|
153
|
+
// @ts-ignore
|
|
154
|
+
sourceMap.astNode = node;
|
|
155
|
+
element.meta.set('sourceMap', sourceMap);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
export default CstVisitor;
|