-
Notifications
You must be signed in to change notification settings - Fork 216
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add yaml parsing support to mappings
- Loading branch information
Showing
4 changed files
with
280 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@graphprotocol/graph-ts': minor | ||
--- | ||
|
||
add yaml support in mappings |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,243 @@ | ||
import { Bytes, Result, TypedMap } from './collections'; | ||
import { BigInt } from './numbers'; | ||
|
||
/** | ||
* Host YAML interface. | ||
*/ | ||
export declare namespace yaml { | ||
/** | ||
* Parses a YAML document from UTF-8 encoded bytes. | ||
* Aborts mapping execution if the bytes cannot be parsed. | ||
*/ | ||
function fromBytes(data: Bytes): YAMLValue; | ||
|
||
/** | ||
* Parses a YAML document from UTF-8 encoded bytes. | ||
* Returns `Result.error == true` if the bytes cannot be parsed. | ||
*/ | ||
function try_fromBytes(data: Bytes): Result<YAMLValue, bool>; | ||
} | ||
|
||
export namespace yaml { | ||
/** | ||
* Parses a YAML document from a UTF-8 encoded string. | ||
* Aborts mapping execution if the string cannot be parsed. | ||
*/ | ||
export function fromString(data: string): YAMLValue { | ||
const bytes = Bytes.fromUTF8(data); | ||
|
||
return yaml.fromBytes(bytes); | ||
} | ||
|
||
/** | ||
* Parses a YAML document from a UTF-8 encoded string. | ||
* Returns `Result.error == true` if the string cannot be parsed. | ||
*/ | ||
export function try_fromString(data: string): Result<YAMLValue, bool> { | ||
const bytes = Bytes.fromUTF8(data); | ||
|
||
return yaml.try_fromBytes(bytes); | ||
} | ||
} | ||
|
||
/** | ||
* All possible YAML value types. | ||
*/ | ||
export enum YAMLValueKind { | ||
NULL = 0, | ||
BOOL = 1, | ||
NUMBER = 2, | ||
STRING = 3, | ||
ARRAY = 4, | ||
OBJECT = 5, | ||
TAGGED = 6, | ||
} | ||
|
||
/** | ||
* Pointer type for `YAMLValue` data. | ||
* | ||
* Big enough to fit any pointer or native `YAMLValue.data`. | ||
*/ | ||
export type YAMLValuePayload = u64; | ||
|
||
export class YAMLValue { | ||
kind: YAMLValueKind; | ||
data: YAMLValuePayload; | ||
|
||
constructor(kind: YAMLValueKind, data: YAMLValuePayload) { | ||
this.kind = kind; | ||
this.data = data; | ||
} | ||
|
||
static newNull(): YAMLValue { | ||
return new YAMLValue(YAMLValueKind.NULL, 0); | ||
} | ||
|
||
static newBool(data: bool): YAMLValue { | ||
return new YAMLValue(YAMLValueKind.BOOL, data ? 1 : 0); | ||
} | ||
|
||
static newI64(data: i64): YAMLValue { | ||
return new YAMLValue(YAMLValueKind.NUMBER, changetype<usize>(data.toString())); | ||
} | ||
|
||
static newU64(data: u64): YAMLValue { | ||
return new YAMLValue(YAMLValueKind.NUMBER, changetype<usize>(data.toString())); | ||
} | ||
|
||
static newF64(data: f64): YAMLValue { | ||
return new YAMLValue(YAMLValueKind.NUMBER, changetype<usize>(data.toString())); | ||
} | ||
|
||
static newBigInt(data: BigInt): YAMLValue { | ||
return new YAMLValue(YAMLValueKind.STRING, changetype<usize>(data.toString())); | ||
} | ||
|
||
static newString(data: string): YAMLValue { | ||
return new YAMLValue(YAMLValueKind.STRING, changetype<usize>(data)); | ||
} | ||
|
||
static newArray(data: Array<YAMLValue>): YAMLValue { | ||
return new YAMLValue(YAMLValueKind.ARRAY, changetype<usize>(data)); | ||
} | ||
|
||
static newObject(data: TypedMap<YAMLValue, YAMLValue>): YAMLValue { | ||
return new YAMLValue(YAMLValueKind.OBJECT, changetype<usize>(data)); | ||
} | ||
|
||
static newTagged(tag: string, value: YAMLValue): YAMLValue { | ||
let tagged = new YAMLTaggedValue(tag, value); | ||
return new YAMLValue(YAMLValueKind.TAGGED, changetype<usize>(tagged)); | ||
} | ||
|
||
isNull(): bool { | ||
return this.kind == YAMLValueKind.NULL; | ||
} | ||
|
||
isBool(): bool { | ||
return this.kind == YAMLValueKind.BOOL; | ||
} | ||
|
||
isNumber(): bool { | ||
return this.kind == YAMLValueKind.NUMBER; | ||
} | ||
|
||
isString(): bool { | ||
return this.kind == YAMLValueKind.STRING; | ||
} | ||
|
||
isArray(): bool { | ||
return this.kind == YAMLValueKind.ARRAY; | ||
} | ||
|
||
isObject(): bool { | ||
return this.kind == YAMLValueKind.OBJECT; | ||
} | ||
|
||
isTagged(): bool { | ||
return this.kind == YAMLValueKind.TAGGED; | ||
} | ||
|
||
toBool(): bool { | ||
assert(this.isBool(), 'YAML value is not a boolean'); | ||
return this.data != 0; | ||
} | ||
|
||
toNumber(): string { | ||
assert(this.isNumber(), 'YAML value is not a number'); | ||
return changetype<string>(this.data as usize); | ||
} | ||
|
||
toI64(): i64 { | ||
return I64.parseInt(this.toNumber()); | ||
} | ||
|
||
toU64(): u64 { | ||
return U64.parseInt(this.toNumber()); | ||
} | ||
|
||
toF64(): f64 { | ||
return F64.parseFloat(this.toNumber()); | ||
} | ||
|
||
toBigInt(): BigInt { | ||
assert(this.isNumber() || this.isString(), 'YAML value is not numeric'); | ||
return BigInt.fromString(changetype<string>(this.data as usize)); | ||
} | ||
|
||
toString(): string { | ||
assert(this.isString(), 'YAML value is not a string'); | ||
return changetype<string>(this.data as usize); | ||
} | ||
|
||
toArray(): Array<YAMLValue> { | ||
assert(this.isArray(), 'YAML value is not an array'); | ||
return changetype<Array<YAMLValue>>(this.data as usize); | ||
} | ||
|
||
toObject(): TypedMap<YAMLValue, YAMLValue> { | ||
assert(this.isObject(), 'YAML value is not an object'); | ||
return changetype<TypedMap<YAMLValue, YAMLValue>>(this.data as usize); | ||
} | ||
|
||
toTagged(): YAMLTaggedValue { | ||
assert(this.isTagged(), 'YAML value is not tagged'); | ||
return changetype<YAMLTaggedValue>(this.data as usize); | ||
} | ||
|
||
// Allows access to YAML values from within an object. | ||
@operator('==') | ||
static __equals(a: YAMLValue, b: YAMLValue): bool { | ||
if (a.isBool() && b.isBool()) { | ||
return a.toBool() == b.toBool() | ||
} | ||
|
||
if (a.isNumber() && b.isNumber()) { | ||
return a.toNumber() == b.toNumber(); | ||
} | ||
|
||
if (a.isString() && b.isString()) { | ||
return a.toString() == b.toString(); | ||
} | ||
|
||
if (a.isTagged() && b.isTagged()) { | ||
return a.toTagged() == b.toTagged(); | ||
} | ||
|
||
return false; | ||
} | ||
|
||
// Makes it easier to access a specific index in a YAML array or a string key in a YAML object. | ||
// | ||
// Examples: | ||
// Usage in YAML objects: `yaml.fromString(subgraphManifest)['specVersion']`; | ||
// Nesting is also supported: `yaml.fromString(subgraphManifest)['schema']['file']`; | ||
// Usage in YAML arrays: `yaml.fromString(subgraphManifest)['dataSources']['0']`; | ||
// YAML arrays and objects: `yaml.fromString(subgraphManifest)['dataSources']['0']['source']['address']`; | ||
@operator('[]') | ||
__get(index: string): YAMLValue { | ||
assert(this.isArray() || this.isObject(), 'YAML value can not be accessed by index'); | ||
|
||
if (this.isArray()) { | ||
return this.toArray()[I32.parseInt(index)]; | ||
} | ||
|
||
return this.toObject().mustGet(YAMLValue.newString(index)); | ||
} | ||
} | ||
|
||
export class YAMLTaggedValue { | ||
tag: string; | ||
value: YAMLValue; | ||
|
||
constructor(tag: string, value: YAMLValue) { | ||
this.tag = tag; | ||
this.value = value; | ||
} | ||
|
||
// Allows access to YAML values from within an object. | ||
@operator('==') | ||
static __equals(a: YAMLTaggedValue, b: YAMLTaggedValue): bool { | ||
return a.tag == b.tag && a.value == b.value; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters