Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(parser-adapter-yaml-1-2): YAML alias syntactic analysis #3785

Merged
merged 5 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/apidom-ast/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export { default as YamlAnchor } from './yaml/nodes/YamlAnchor';
export { YamlStyle, YamlStyleGroup } from './yaml/nodes/YamlStyle';
export { default as YamlFailsafeSchema } from './yaml/schemas/failsafe/index';
export { default as YamlJsonSchema } from './yaml/schemas/json/index';
export { default as YamlReferenceManager } from './yaml/anchors-aliases/ReferenceManager';
export {
isAlias as isYamlAlias,
isKeyValuePair as isYamlKeyValuePair,
Expand Down
20 changes: 20 additions & 0 deletions packages/apidom-ast/src/yaml/anchors-aliases/ReferenceManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import YamlAlias from '../nodes/YamlAlias';
import YamlAnchor from '../nodes/YamlAnchor';
import YamlScalar from '../nodes/YamlScalar';
import { YamlStyle, YamlStyleGroup } from '../nodes/YamlStyle';

class ReferenceManager {
// eslint-disable-next-line @typescript-eslint/no-unused-vars, class-methods-use-this
addAnchor(anchor: YamlAnchor): void {}

// eslint-disable-next-line class-methods-use-this
resolveAlias(alias: YamlAlias): YamlScalar {
return new YamlScalar({
content: alias.content,
style: YamlStyle.Plain,
styleGroup: YamlStyleGroup.Flow,
});
}
}

export default ReferenceManager;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Tree as NodeTree } from 'tree-sitter';
import { Tree as WebTree } from 'web-tree-sitter';
import { ParseResultElement } from '@swagger-api/apidom-core';
import { visit, YamlJsonSchema as JsonSchema } from '@swagger-api/apidom-ast';
import { visit, YamlJsonSchema as JsonSchema, YamlReferenceManager } from '@swagger-api/apidom-ast';

import CstVisitor, { keyMap as cstKeyMap, isNode as isCstNode } from './visitors/CstVisitor';
import YamlAstVisitor, {
Expand All @@ -25,6 +25,7 @@ const analyze = (cst: Tree, { sourceMap = false } = {}): ParseResultElement => {
const cstVisitor = new CstVisitor();
const astVisitor = new YamlAstVisitor();
const schema = new JsonSchema();
const referenceManager = new YamlReferenceManager();

const yamlAst = visit(rootNode, cstVisitor, {
// @ts-ignore
Expand All @@ -33,6 +34,7 @@ const analyze = (cst: Tree, { sourceMap = false } = {}): ParseResultElement => {
state: {
schema,
sourceMap,
referenceManager,
},
});

Expand Down
char0n marked this conversation as resolved.
Show resolved Hide resolved
char0n marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import {
ParseResult,
Point,
Position,
YamlAlias,
YamlAnchor,
YamlComment,
YamlDirective,
YamlDocument,
YamlKeyValuePair,
YamlMapping,
YamlNodeKind,
YamlReferenceManager,
YamlScalar,
YamlSequence,
YamlStream,
Expand Down Expand Up @@ -95,89 +97,11 @@ class CstVisitor {
return new YamlTag({ explicitName, kind, position });
}

private static kindNodeToYamlAnchor(node: TreeCursorSyntaxNode): YamlAnchor | undefined {
const { anchor: anchorNode } = node;

if (typeof anchorNode === 'undefined') return undefined;

return new YamlAnchor({ name: anchorNode.text, position: CstVisitor.toPosition(anchorNode) });
}

private static createKeyValuePairEmptyKey(node: TreeCursorSyntaxNode): YamlScalar {
const emptyPoint = new Point({
row: node.startPosition.row,
column: node.startPosition.column,
char: node.startIndex,
});
const { keyNode } = node;
const children = keyNode?.children || [];
const tagNode = children.find(CstVisitor.isKind('tag'));
const anchorNode = children.find(CstVisitor.isKind('anchor'));
const tag =
typeof tagNode !== 'undefined'
? new YamlTag({
explicitName: tagNode.text,
kind: YamlNodeKind.Scalar,
position: CstVisitor.toPosition(tagNode),
})
: new YamlTag({
explicitName: '?',
kind: YamlNodeKind.Scalar,
});
const anchor =
typeof anchorNode !== 'undefined'
? new YamlAnchor({ name: anchorNode.text, position: CstVisitor.toPosition(anchorNode) })
: undefined;

return new YamlScalar({
content: '',
position: new Position({ start: emptyPoint, end: emptyPoint }),
tag,
anchor,
styleGroup: YamlStyleGroup.Flow,
style: YamlStyle.Plain,
});
}

private static createKeyValuePairEmptyValue(node: TreeCursorSyntaxNode): YamlScalar {
const emptyPoint = new Point({
row: node.endPosition.row,
column: node.endPosition.column,
char: node.endIndex,
});
const { valueNode } = node;
const children = valueNode?.children || [];
const tagNode = children.find(CstVisitor.isKind('tag'));
const anchorNode = children.find(CstVisitor.isKind('anchor'));
const tag =
typeof tagNode !== 'undefined'
? new YamlTag({
explicitName: tagNode.text,
kind: YamlNodeKind.Scalar,
position: CstVisitor.toPosition(tagNode),
})
: new YamlTag({
explicitName: '?',
kind: YamlNodeKind.Scalar,
});
const anchor =
typeof anchorNode !== 'undefined'
? new YamlAnchor({ name: anchorNode.text, position: CstVisitor.toPosition(anchorNode) })
: undefined;

return new YamlScalar({
content: '',
position: new Position({ start: emptyPoint, end: emptyPoint }),
tag,
anchor,
styleGroup: YamlStyleGroup.Flow,
style: YamlStyle.Plain,
});
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
public schema!: any;

public referenceManager!: YamlReferenceManager;

public readonly stream = {
enter: (node: TreeCursorSyntaxNode): YamlStream => {
const position = CstVisitor.toPosition(node);
Expand Down Expand Up @@ -288,7 +212,7 @@ class CstVisitor {
});
const emptyScalarNode = new YamlScalar({
content: '',
anchor: CstVisitor.kindNodeToYamlAnchor(kindCandidate),
anchor: this.kindNodeToYamlAnchor(kindCandidate),
tag: CstVisitor.kindNodeToYamlTag(kindCandidate),
position: new Position({ start: emptyPoint, end: emptyPoint }),
styleGroup: YamlStyleGroup.Flow,
Expand All @@ -315,7 +239,7 @@ class CstVisitor {
enter: (node: TreeCursorSyntaxNode) => {
const position = CstVisitor.toPosition(node);
const tag = CstVisitor.kindNodeToYamlTag(node);
const anchor = CstVisitor.kindNodeToYamlAnchor(node);
const anchor = this.kindNodeToYamlAnchor(node);
const mappingNode = new YamlMapping({
children: node.children,
position,
Expand All @@ -336,11 +260,11 @@ class CstVisitor {
const children: Array<TreeCursorSyntaxNode | YamlScalar> = [...node.children];

if (CstVisitor.hasKeyValuePairEmptyKey(node)) {
const keyNode = CstVisitor.createKeyValuePairEmptyKey(node);
const keyNode = this.createKeyValuePairEmptyKey(node);
children.unshift(keyNode);
}
if (CstVisitor.hasKeyValuePairEmptyValue(node)) {
const valueNode = CstVisitor.createKeyValuePairEmptyValue(node);
const valueNode = this.createKeyValuePairEmptyValue(node);
children.push(valueNode);
}

Expand All @@ -357,7 +281,7 @@ class CstVisitor {
enter: (node: TreeCursorSyntaxNode) => {
const position = CstVisitor.toPosition(node);
const tag = CstVisitor.kindNodeToYamlTag(node);
const anchor = CstVisitor.kindNodeToYamlAnchor(node);
const anchor = this.kindNodeToYamlAnchor(node);
const mappingNode = new YamlMapping({
children: node.children,
position,
Expand All @@ -378,11 +302,11 @@ class CstVisitor {
const children: Array<TreeCursorSyntaxNode | YamlScalar> = [...node.children];

if (CstVisitor.hasKeyValuePairEmptyKey(node)) {
const keyNode = CstVisitor.createKeyValuePairEmptyKey(node);
const keyNode = this.createKeyValuePairEmptyKey(node);
children.unshift(keyNode);
}
if (CstVisitor.hasKeyValuePairEmptyValue(node)) {
const valueNode = CstVisitor.createKeyValuePairEmptyValue(node);
const valueNode = this.createKeyValuePairEmptyValue(node);
children.push(valueNode);
}

Expand All @@ -405,7 +329,7 @@ class CstVisitor {
enter: (node: TreeCursorSyntaxNode) => {
const position = CstVisitor.toPosition(node);
const tag = CstVisitor.kindNodeToYamlTag(node);
const anchor = CstVisitor.kindNodeToYamlAnchor(node);
const anchor = this.kindNodeToYamlAnchor(node);
const sequenceNode = new YamlSequence({
children: node.children,
position,
Expand Down Expand Up @@ -451,7 +375,7 @@ class CstVisitor {
enter: (node: TreeCursorSyntaxNode) => {
const position = CstVisitor.toPosition(node);
const tag = CstVisitor.kindNodeToYamlTag(node);
const anchor = CstVisitor.kindNodeToYamlAnchor(node);
const anchor = this.kindNodeToYamlAnchor(node);
const sequenceNode = new YamlSequence({
children: node.children.flat(),
position,
Expand All @@ -475,7 +399,7 @@ class CstVisitor {
enter: (node: TreeCursorSyntaxNode) => {
const position = CstVisitor.toPosition(node);
const tag = CstVisitor.kindNodeToYamlTag(node);
const anchor = CstVisitor.kindNodeToYamlAnchor(node);
const anchor = this.kindNodeToYamlAnchor(node);
const scalarNode = new YamlScalar({
content: node.text,
anchor,
Expand All @@ -493,7 +417,7 @@ class CstVisitor {
enter: (node: TreeCursorSyntaxNode) => {
const position = CstVisitor.toPosition(node);
const tag = CstVisitor.kindNodeToYamlTag(node);
const anchor = CstVisitor.kindNodeToYamlAnchor(node);
const anchor = this.kindNodeToYamlAnchor(node);
const scalarNode = new YamlScalar({
content: node.text,
anchor,
Expand All @@ -511,7 +435,7 @@ class CstVisitor {
enter: (node: TreeCursorSyntaxNode) => {
const position = CstVisitor.toPosition(node);
const tag = CstVisitor.kindNodeToYamlTag(node);
const anchor = CstVisitor.kindNodeToYamlAnchor(node);
const anchor = this.kindNodeToYamlAnchor(node);
const scalarNode = new YamlScalar({
content: node.text,
anchor,
Expand All @@ -529,7 +453,7 @@ class CstVisitor {
enter: (node: TreeCursorSyntaxNode) => {
const position = CstVisitor.toPosition(node);
const tag = CstVisitor.kindNodeToYamlTag(node);
const anchor = CstVisitor.kindNodeToYamlAnchor(node);
const anchor = this.kindNodeToYamlAnchor(node);
const style = node.text.startsWith('|')
? YamlStyle.Literal
: node.text.startsWith('>')
Expand All @@ -554,6 +478,14 @@ class CstVisitor {
},
};

public readonly alias = {
enter: (node: TreeCursorSyntaxNode) => {
const alias = new YamlAlias({ content: node.text });

return this.referenceManager.resolveAlias(alias);
},
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
constructor(schema?: any) {
this.schema = schema;
Expand Down Expand Up @@ -595,6 +527,100 @@ class CstVisitor {

return errorNode;
}

private kindNodeToYamlAnchor(node: TreeCursorSyntaxNode): YamlAnchor | undefined {
const { anchor: anchorNode } = node;

if (typeof anchorNode === 'undefined') return undefined;

const anchor = new YamlAnchor({
name: anchorNode.text,
position: CstVisitor.toPosition(anchorNode),
});
this.referenceManager.addAnchor(anchor);

return anchor;
}

private createKeyValuePairEmptyKey(node: TreeCursorSyntaxNode): YamlScalar {
const emptyPoint = new Point({
row: node.startPosition.row,
column: node.startPosition.column,
char: node.startIndex,
});
const { keyNode } = node;
const children = keyNode?.children || [];
const tagNode = children.find(CstVisitor.isKind('tag'));
const anchorNode = children.find(CstVisitor.isKind('anchor'));
const tag =
typeof tagNode !== 'undefined'
? new YamlTag({
explicitName: tagNode.text,
kind: YamlNodeKind.Scalar,
position: CstVisitor.toPosition(tagNode),
})
: new YamlTag({
explicitName: '?',
kind: YamlNodeKind.Scalar,
});
const anchor =
typeof anchorNode !== 'undefined'
? new YamlAnchor({ name: anchorNode.text, position: CstVisitor.toPosition(anchorNode) })
: undefined;

if (anchor !== undefined) {
this.referenceManager.addAnchor(anchor);
}

return new YamlScalar({
content: '',
position: new Position({ start: emptyPoint, end: emptyPoint }),
tag,
anchor,
styleGroup: YamlStyleGroup.Flow,
style: YamlStyle.Plain,
});
}

private createKeyValuePairEmptyValue(node: TreeCursorSyntaxNode): YamlScalar {
const emptyPoint = new Point({
row: node.endPosition.row,
column: node.endPosition.column,
char: node.endIndex,
});
const { valueNode } = node;
const children = valueNode?.children || [];
const tagNode = children.find(CstVisitor.isKind('tag'));
const anchorNode = children.find(CstVisitor.isKind('anchor'));
const tag =
typeof tagNode !== 'undefined'
? new YamlTag({
explicitName: tagNode.text,
kind: YamlNodeKind.Scalar,
position: CstVisitor.toPosition(tagNode),
})
: new YamlTag({
explicitName: '?',
kind: YamlNodeKind.Scalar,
});
const anchor =
typeof anchorNode !== 'undefined'
? new YamlAnchor({ name: anchorNode.text, position: CstVisitor.toPosition(anchorNode) })
: undefined;

if (anchor !== undefined) {
this.referenceManager.addAnchor(anchor);
}

return new YamlScalar({
content: '',
position: new Position({ start: emptyPoint, end: emptyPoint }),
tag,
anchor,
styleGroup: YamlStyleGroup.Flow,
style: YamlStyle.Plain,
});
}
}

export default CstVisitor;