preserves/implementations/javascript/packages/core/src/annotated.ts

62 lines
1.6 KiB
TypeScript
Raw Normal View History

2021-03-02 21:54:42 +00:00
import { Encoder } from "./encoder";
import { Tag } from "./constants";
import { AsPreserve, PreserveOn } from "./symbols";
import { DefaultPointer, Value } from "./values";
import { is, isAnnotated, IsPreservesAnnotated } from "./is";
import { stringify } from "./text";
export class Annotated<T = DefaultPointer> {
readonly annotations: Array<Value<T>>;
readonly item: Value<T>;
constructor(item: Value<T>) {
this.annotations = [];
this.item = item;
}
[AsPreserve](): Value<T> {
return this;
}
[PreserveOn](encoder: Encoder<T>) {
if (encoder.includeAnnotations) {
for (const a of this.annotations) {
encoder.emitbyte(Tag.Annotation);
encoder.push(a);
}
}
encoder.push(this.item);
}
equals(other: any): boolean {
return is(this.item, Annotated.isAnnotated(other) ? other.item : other);
}
// hashCode(): number {
// return hash(this.item);
// }
toString(): string {
return this.asPreservesText();
}
asPreservesText(): string {
const anns = this.annotations.map((a) => '@' + stringify(a)).join(' ');
return (anns ? anns + ' ' : anns) + stringify(this.item);
}
get [IsPreservesAnnotated](): boolean {
return true;
}
static isAnnotated<T = DefaultPointer>(x: any): x is Annotated<T> {
return isAnnotated(x);
}
}
export function annotate<T = DefaultPointer>(v0: Value<T>, ...anns: Value<T>[]): Annotated<T> {
const v = Annotated.isAnnotated<T>(v0) ? v0 : new Annotated(v0);
anns.forEach((a) => v.annotations.push(a));
return v;
}