/*
* Copyright 2025 the original author or authors.
*
* Licensed under the Moderne Source Available License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://docs.moderne.io/licensing/moderne-source-available-license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {mapAsync, updateIfChanged} from "../util";
import {TreeVisitor} from "../visitor";
import {SourceFile} from "../tree";
import {isYaml, Yaml} from "./tree";
export class YamlVisitor
extends TreeVisitor {
async isAcceptable(sourceFile: SourceFile): Promise {
return isYaml(sourceFile);
}
protected async visitDocuments(documents: Yaml.Documents, p: P): Promise {
const updates: any = {
markers: await this.visitMarkers(documents.markers, p),
documents: await mapAsync(documents.documents, doc => this.visitDefined(doc, p) as Promise)
};
return updateIfChanged(documents, updates);
}
protected async visitDocument(document: Yaml.Document, p: P): Promise {
const updates: any = {
markers: await this.visitMarkers(document.markers, p),
directives: await mapAsync(document.directives, d => this.visitDefined(d, p) as Promise),
block: await this.visitDefined(document.block, p),
end: await this.visitDefined(document.end, p)
};
return updateIfChanged(document, updates);
}
protected async visitDirective(directive: Yaml.Directive, p: P): Promise {
const updates: any = {
markers: await this.visitMarkers(directive.markers, p)
};
return updateIfChanged(directive, updates);
}
protected async visitDocumentEnd(end: Yaml.DocumentEnd, p: P): Promise {
const updates: any = {
markers: await this.visitMarkers(end.markers, p)
};
return updateIfChanged(end, updates);
}
protected async visitMapping(mapping: Yaml.Mapping, p: P): Promise {
const updates: any = {
markers: await this.visitMarkers(mapping.markers, p),
tag: mapping.tag ? await this.visit(mapping.tag, p) : undefined,
anchor: mapping.anchor ? await this.visit(mapping.anchor, p) : undefined,
entries: await mapAsync(mapping.entries, entry => this.visitDefined(entry, p) as Promise)
};
return updateIfChanged(mapping, updates);
}
protected async visitMappingEntry(entry: Yaml.MappingEntry, p: P): Promise {
const updates: any = {
markers: await this.visitMarkers(entry.markers, p),
key: await this.visitDefined(entry.key, p),
value: await this.visitDefined(entry.value, p)
};
return updateIfChanged(entry, updates);
}
protected async visitScalar(scalar: Yaml.Scalar, p: P): Promise {
const updates: any = {
markers: await this.visitMarkers(scalar.markers, p),
anchor: scalar.anchor ? await this.visit(scalar.anchor, p) : undefined,
tag: scalar.tag ? await this.visit(scalar.tag, p) : undefined
};
return updateIfChanged(scalar, updates);
}
protected async visitSequence(sequence: Yaml.Sequence, p: P): Promise {
const updates: any = {
markers: await this.visitMarkers(sequence.markers, p),
tag: sequence.tag ? await this.visit(sequence.tag, p) : undefined,
anchor: sequence.anchor ? await this.visit(sequence.anchor, p) : undefined,
entries: await mapAsync(sequence.entries, entry => this.visitDefined(entry, p) as Promise)
};
return updateIfChanged(sequence, updates);
}
protected async visitSequenceEntry(entry: Yaml.SequenceEntry, p: P): Promise {
const updates: any = {
markers: await this.visitMarkers(entry.markers, p),
block: await this.visitDefined(entry.block, p)
};
return updateIfChanged(entry, updates);
}
protected async visitAnchor(anchor: Yaml.Anchor, p: P): Promise {
const updates: any = {
markers: await this.visitMarkers(anchor.markers, p)
};
return updateIfChanged(anchor, updates);
}
protected async visitAlias(alias: Yaml.Alias, p: P): Promise {
const updates: any = {
markers: await this.visitMarkers(alias.markers, p),
anchor: await this.visitDefined(alias.anchor, p)
};
return updateIfChanged(alias, updates);
}
protected async visitTag(tag: Yaml.Tag, p: P): Promise {
const updates: any = {
markers: await this.visitMarkers(tag.markers, p)
};
return updateIfChanged(tag, updates);
}
protected accept(t: Yaml, p: P): Promise {
switch (t.kind) {
case Yaml.Kind.Documents:
return this.visitDocuments(t as Yaml.Documents, p);
case Yaml.Kind.Document:
return this.visitDocument(t as Yaml.Document, p);
case Yaml.Kind.DocumentEnd:
return this.visitDocumentEnd(t as Yaml.DocumentEnd, p);
case Yaml.Kind.Directive:
return this.visitDirective(t as Yaml.Directive, p);
case Yaml.Kind.Mapping:
return this.visitMapping(t as Yaml.Mapping, p);
case Yaml.Kind.MappingEntry:
return this.visitMappingEntry(t as Yaml.MappingEntry, p);
case Yaml.Kind.Scalar:
return this.visitScalar(t as Yaml.Scalar, p);
case Yaml.Kind.Sequence:
return this.visitSequence(t as Yaml.Sequence, p);
case Yaml.Kind.SequenceEntry:
return this.visitSequenceEntry(t as Yaml.SequenceEntry, p);
case Yaml.Kind.Anchor:
return this.visitAnchor(t as Yaml.Anchor, p);
case Yaml.Kind.Alias:
return this.visitAlias(t as Yaml.Alias, p);
case Yaml.Kind.Tag:
return this.visitTag(t as Yaml.Tag, p);
default:
throw new Error(`Unexpected YAML kind ${(t as any).kind}`);
}
}
}