diff --git a/Makefile b/Makefile index 82a56c8..5b792ae 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ verify: mempool.s9pk $(S9PK_PATH) install: mempool.s9pk embassy-cli package install mempool.s9pk -mempool.s9pk: manifest.yaml assets/* image.tar docs/instructions.md +mempool.s9pk: manifest.yaml assets/* image.tar docs/instructions.md scripts/embassy.js embassy-sdk pack instructions.md: README.md @@ -27,3 +27,6 @@ clean: rm -f mempool.s9pk rm -f image.tar +scripts/embassy.js: scripts/**/*.ts + deno cache --reload scripts/embassy.ts + deno bundle scripts/embassy.ts scripts/embassy.js diff --git a/manifest.yaml b/manifest.yaml index eb6a2c7..205b0c3 100644 --- a/manifest.yaml +++ b/manifest.yaml @@ -1,7 +1,7 @@ id: mempool title: Mempool -version: 2.4.0 -release-notes: Update to Mempool v2.4.0 - added mining tab and additional reporting +version: 2.4.0.1 +release-notes: Update to Mempool v2.4.0.1 - added js procedures for EOS performance improvements license: AGPL wrapper-repo: "https://github.com/Start9Labs/mempool-wrapper" upstream-repo: "https://github.com/mempool/mempool" @@ -61,87 +61,23 @@ health-checks: inject: true config: get: - type: docker - image: compat - system: true - entrypoint: compat - args: - - config - - get - - /root - - "/mnt/assets/config_spec.yaml" - mounts: - compat: /mnt/assets - main: /root - io-format: yaml + type: script set: - type: docker - image: compat - system: true - entrypoint: compat - args: - - config - - set - - "mempool" - - /root - - "/mnt/assets/config_rules.yaml" - - "/mnt/assets/dependencies.yaml" - mounts: - compat: /mnt/assets - main: /root - io-format: yaml + type: script properties: - type: docker - image: compat - system: true - entrypoint: compat - args: - - properties - - /root - mounts: - main: /root - compat: /mnt/assets - io-format: yaml + type: script dependencies: bitcoind: version: ">=0.21.1.2 <24.0.0" requirement: type: "opt-out" how: Can alternatively configure proxy or bitcoin core node. - description: Used to subscribe to new block events from a full archival node. + description: Used to subscribe to new block events from a full archival node config: - check: - type: docker - image: compat - system: true - entrypoint: compat - args: - - dependency - - check - - "mempool" - - bitcoind - - /root - - "/mnt/assets/bitcoind_config_rules.yaml" - mounts: - compat: /mnt/assets - main: /root - io-format: yaml + check: + type: script auto-configure: - type: docker - image: compat - system: true - entrypoint: compat - args: - - dependency - - "auto-configure" - - "mempool" - - bitcoind - - /root - - "/mnt/assets/bitcoind_config_rules.yaml" - mounts: - compat: /mnt/assets - main: /root - io-format: yaml + type: script btc-rpc-proxy: version: ">=0.3.2.1 <0.4.0" requirement: @@ -150,37 +86,9 @@ dependencies: description: Used for RPC permissioning. config: check: - type: docker - image: compat - system: true - entrypoint: compat - args: - - dependency - - check - - mempool - - "btc-rpc-proxy" - - /root - - "/mnt/assets/btc-rpc-proxy_config_rules.yaml" - mounts: - main: /root - compat: /mnt/assets - io-format: yaml + type: script auto-configure: - type: docker - image: compat - system: true - entrypoint: compat - args: - - dependency - - "auto-configure" - - mempool - - "btc-rpc-proxy" - - /root - - "/mnt/assets/btc-rpc-proxy_config_rules.yaml" - mounts: - main: /root - compat: /mnt/assets - io-format: yaml + type: script electrs: version: ">=0.9.6 <0.10.0" requirement: diff --git a/migrations/eq_22_0_0.sh b/migrations/eq_22_0_0.sh new file mode 100644 index 0000000..7e63920 --- /dev/null +++ b/migrations/eq_22_0_0.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -ea + +if [ $1 = "from" ]; then + yq -i '.advanced.peers.addnode |= map(select(.hostname != ~))' /root/.bitcoin/start9/config.yaml + yq -i '.advanced.bloomfilters.peerbloomfilters = false' /root/.bitcoin/start9/config.yaml + echo '{"configured": true }' + exit 0 +elif [ $1 = "to" ]; then + yq -i 'del(.advanced.bloomfilters)' /root/.bitcoin/start9/config.yaml + echo '{"configured": false }' + exit 0 +else + echo "FATAL: Invalid argument: {from, to}. Migration failed." >&2 + exit 1 +fi diff --git a/migrations/gt_22_0_0_lt_23_0_0.sh b/migrations/gt_22_0_0_lt_23_0_0.sh new file mode 100644 index 0000000..bfa749d --- /dev/null +++ b/migrations/gt_22_0_0_lt_23_0_0.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +set -ea + +if [ $1 = "from" ]; then + yq -i '.advanced.peers.addnode |= map(select(.hostname != ~ or . == "*"))' /root/.bitcoin/start9/config.yaml + yq -i '.advanced.peers.addnode.[] |= {"hostname":., "port":~}' /root/.bitcoin/start9/config.yaml + yq -i '(.advanced.blockfilters.blockfilterindex, .advanced.blockfilters.peerblockfilters, .advanced.bloomfilters.peerbloomfilters) = false' /root/.bitcoin/start9/config.yaml + echo '{"configured": true }' + exit 0 +elif [ $1 = "to" ]; then + yq -i '.advanced.peers.addnode |= map_values(.hostname)' /root/.bitcoin/start9/config.yaml + yq -i 'del(.advanced.bloomfilters)' /root/.bitcoin/start9/config.yaml + echo '{"configured": false }' + exit 0 +else + echo "FATAL: Invalid argument: {from, to}. Migration failed." >&2 + exit 1 +fi +`` \ No newline at end of file diff --git a/scripts/.gitignore b/scripts/.gitignore new file mode 100644 index 0000000..4c43fe6 --- /dev/null +++ b/scripts/.gitignore @@ -0,0 +1 @@ +*.js \ No newline at end of file diff --git a/scripts/deps.ts b/scripts/deps.ts new file mode 100644 index 0000000..d64639e --- /dev/null +++ b/scripts/deps.ts @@ -0,0 +1,14 @@ +import matches from "https://deno.land/x/ts_matches@5.1.5/mod.ts"; +export * as YAML from "https://deno.land/std@0.140.0/encoding/yaml.ts"; +export type { + Config, + ConfigRes, + Effects, + ExpectedExports, + KnownError, + PackagePropertiesV2, + Properties, + SetResult, +} from "https://start9.com/procedure/types.0.3.1.d.ts"; + +export { matches }; diff --git a/scripts/embassy.js b/scripts/embassy.js new file mode 100644 index 0000000..7dfa076 --- /dev/null +++ b/scripts/embassy.js @@ -0,0 +1,4309 @@ +// deno-fmt-ignore-file +// deno-lint-ignore-file +// This code was bundled using `deno bundle` and it's not recommended to edit it manually + +function saferStringify(x) { + try { + return JSON.stringify(x); + } catch (e) { + return "" + x; + } +} +class AnyParser { + constructor(description = { + name: "Any", + children: [], + extras: [] + }){ + this.description = description; + } + parse(a, onParse) { + return onParse.parsed(a); + } + description; +} +class ArrayParser { + constructor(description = { + name: "Array", + children: [], + extras: [] + }){ + this.description = description; + } + parse(a, onParse) { + if (Array.isArray(a)) return onParse.parsed(a); + return onParse.invalid({ + value: a, + keys: [], + parser: this + }); + } + description; +} +class BoolParser { + constructor(description = { + name: "Boolean", + children: [], + extras: [] + }){ + this.description = description; + } + parse(a, onParse) { + if (a === true || a === false) return onParse.parsed(a); + return onParse.invalid({ + value: a, + keys: [], + parser: this + }); + } + description; +} +const isObject = (x)=>typeof x === "object" && x != null; +const isFunctionTest = (x)=>typeof x === "function"; +const isNumber = (x)=>typeof x === "number"; +const isString = (x)=>typeof x === "string"; +const booleanOnParse = { + parsed (_) { + return true; + }, + invalid (_) { + return false; + } +}; +class FunctionParser { + constructor(description = { + name: "Function", + children: [], + extras: [] + }){ + this.description = description; + } + parse(a, onParse) { + if (isFunctionTest(a)) return onParse.parsed(a); + return onParse.invalid({ + value: a, + keys: [], + parser: this + }); + } + description; +} +class NilParser { + constructor(description = { + name: "Null", + children: [], + extras: [] + }){ + this.description = description; + } + parse(a, onParse) { + if (a === null || a === undefined) return onParse.parsed(a); + return onParse.invalid({ + value: a, + keys: [], + parser: this + }); + } + description; +} +class ObjectParser { + constructor(description = { + name: "Object", + children: [], + extras: [] + }){ + this.description = description; + } + parse(a, onParse) { + if (isObject(a)) return onParse.parsed(a); + return onParse.invalid({ + value: a, + keys: [], + parser: this + }); + } + description; +} +class StringParser { + constructor(description = { + name: "String", + children: [], + extras: [] + }){ + this.description = description; + } + parse(a, onParse) { + if (isString(a)) return onParse.parsed(a); + return onParse.invalid({ + value: a, + keys: [], + parser: this + }); + } + description; +} +class UnknownParser { + constructor(description = { + name: "Unknown", + children: [], + extras: [] + }){ + this.description = description; + } + parse(a, onParse) { + return onParse.parsed(a); + } + description; +} +class ConcatParsers { + constructor(parent, otherParser, description = { + name: "Concat", + children: [ + parent, + otherParser + ], + extras: [] + }){ + this.parent = parent; + this.otherParser = otherParser; + this.description = description; + } + static of(parent, otherParser) { + if (parent.unwrappedParser().description.name === "Any") { + return otherParser; + } + if (otherParser.unwrappedParser().description.name === "Any") { + return parent; + } + return new ConcatParsers(parent, otherParser); + } + parse(a, onParse) { + const parent = this.parent.enumParsed(a); + if ("error" in parent) { + return onParse.invalid(parent.error); + } + const other = this.otherParser.enumParsed(parent.value); + if ("error" in other) { + return onParse.invalid(other.error); + } + return onParse.parsed(other.value); + } + parent; + otherParser; + description; +} +class DefaultParser { + constructor(parent, defaultValue, description = { + name: "Default", + children: [ + parent + ], + extras: [ + defaultValue + ] + }){ + this.parent = parent; + this.defaultValue = defaultValue; + this.description = description; + } + parse(a, onParse) { + const parser = this; + const defaultValue = this.defaultValue; + if (a == null) { + return onParse.parsed(defaultValue); + } + const parentCheck = this.parent.enumParsed(a); + if ("error" in parentCheck) { + parentCheck.error.parser = parser; + return onParse.invalid(parentCheck.error); + } + return onParse.parsed(parentCheck.value); + } + parent; + defaultValue; + description; +} +class GuardParser { + constructor(checkIsA, typeName, description = { + name: "Guard", + children: [], + extras: [ + typeName + ] + }){ + this.checkIsA = checkIsA; + this.typeName = typeName; + this.description = description; + } + parse(a, onParse) { + if (this.checkIsA(a)) { + return onParse.parsed(a); + } + return onParse.invalid({ + value: a, + keys: [], + parser: this + }); + } + checkIsA; + typeName; + description; +} +class MappedAParser { + constructor(parent, map, mappingName = map.name, description = { + name: "Mapped", + children: [ + parent + ], + extras: [ + mappingName + ] + }){ + this.parent = parent; + this.map = map; + this.mappingName = mappingName; + this.description = description; + } + parse(a, onParse) { + const map = this.map; + const result = this.parent.enumParsed(a); + if ("error" in result) { + return onParse.invalid(result.error); + } + return onParse.parsed(map(result.value)); + } + parent; + map; + mappingName; + description; +} +class MaybeParser { + constructor(parent, description = { + name: "Maybe", + children: [ + parent + ], + extras: [] + }){ + this.parent = parent; + this.description = description; + } + parse(a, onParse) { + if (a == null) { + return onParse.parsed(null); + } + const parser = this; + const parentState = this.parent.enumParsed(a); + if ("error" in parentState) { + const { error } = parentState; + error.parser = parser; + return onParse.invalid(error); + } + return onParse.parsed(parentState.value); + } + parent; + description; +} +class OrParsers { + constructor(parent, otherParser, description = { + name: "Or", + children: [ + parent, + otherParser + ], + extras: [] + }){ + this.parent = parent; + this.otherParser = otherParser; + this.description = description; + } + parse(a, onParse) { + const parser = this; + const parent = this.parent.enumParsed(a); + if ("value" in parent) { + return onParse.parsed(parent.value); + } + const other = this.otherParser.enumParsed(a); + if ("error" in other) { + const { error } = other; + error.parser = parser; + return onParse.invalid(error); + } + return onParse.parsed(other.value); + } + parent; + otherParser; + description; +} +class NumberParser { + constructor(description = { + name: "Number", + children: [], + extras: [] + }){ + this.description = description; + } + parse(a, onParse) { + if (isNumber(a)) return onParse.parsed(a); + return onParse.invalid({ + value: a, + keys: [], + parser: this + }); + } + description; +} +function unwrapParser(a) { + if (a instanceof Parser) return unwrapParser(a.parser); + return a; +} +const enumParsed = { + parsed (value) { + return { + value + }; + }, + invalid (error) { + return { + error + }; + } +}; +class Parser { + _TYPE; + constructor(parser, description = { + name: "Wrapper", + children: [ + parser + ], + extras: [] + }){ + this.parser = parser; + this.description = description; + this._TYPE = null; + this.test = (value)=>{ + return this.parse(value, booleanOnParse); + }; + } + parse(a, onParse) { + return this.parser.parse(a, onParse); + } + static isA(checkIsA, name) { + return new Parser(new GuardParser(checkIsA, name)); + } + static validatorErrorAsString = (error)=>{ + const { parser , value , keys } = error; + const keysString = !keys.length ? "" : keys.map((x)=>`[${x}]`).reverse().join(""); + return `${keysString}${Parser.parserAsString(parser)}(${saferStringify(value)})`; + }; + static parserAsString(parserComingIn) { + const parser = unwrapParser(parserComingIn); + const { description: { name , extras , children } , } = parser; + if (parser instanceof ShapeParser) { + return `${name}<{${parser.description.children.map((subParser, i)=>`${String(parser.description.extras[i]) || "?"}:${Parser.parserAsString(subParser)}`).join(",")}}>`; + } + if (parser instanceof OrParsers) { + const parent = unwrapParser(parser.parent); + const parentString = Parser.parserAsString(parent); + if (parent instanceof OrParsers) return parentString; + return `${name}<${parentString},...>`; + } + if (parser instanceof GuardParser) { + return String(extras[0] || name); + } + if (parser instanceof StringParser || parser instanceof ObjectParser || parser instanceof NumberParser || parser instanceof BoolParser || parser instanceof AnyParser) { + return name.toLowerCase(); + } + if (parser instanceof FunctionParser) { + return name; + } + if (parser instanceof NilParser) { + return "null"; + } + if (parser instanceof ArrayParser) { + return "Array"; + } + const specifiers = [ + ...extras.map(saferStringify), + ...children.map(Parser.parserAsString), + ]; + const specifiersString = `<${specifiers.join(",")}>`; + !children.length ? "" : `<>`; + return `${name}${specifiersString}`; + } + unsafeCast(value) { + const state = this.enumParsed(value); + if ("value" in state) return state.value; + const { error } = state; + throw new TypeError(`Failed type: ${Parser.validatorErrorAsString(error)} given input ${saferStringify(value)}`); + } + castPromise(value) { + const state = this.enumParsed(value); + if ("value" in state) return Promise.resolve(state.value); + const { error } = state; + return Promise.reject(new TypeError(`Failed type: ${Parser.validatorErrorAsString(error)} given input ${saferStringify(value)}`)); + } + map(fn, mappingName) { + return new Parser(new MappedAParser(this, fn, mappingName)); + } + concat(otherParser) { + return new Parser(ConcatParsers.of(this, new Parser(otherParser))); + } + orParser(otherParser) { + return new Parser(new OrParsers(this, new Parser(otherParser))); + } + test; + optional(name) { + return new Parser(new MaybeParser(this)); + } + defaultTo(defaultValue) { + return new Parser(new DefaultParser(new Parser(new MaybeParser(this)), defaultValue)); + } + validate(isValid, otherName) { + return new Parser(ConcatParsers.of(this, new Parser(new GuardParser(isValid, otherName)))); + } + refine(refinementTest, otherName = refinementTest.name) { + return new Parser(ConcatParsers.of(this, new Parser(new GuardParser(refinementTest, otherName)))); + } + name(nameString) { + return parserName(nameString, this); + } + enumParsed(value) { + return this.parse(value, enumParsed); + } + unwrappedParser() { + let answer = this; + while(true){ + const next = answer.parser; + if (next instanceof Parser) { + answer = next; + } else { + return next; + } + } + } + parser; + description; +} +function guard(test, testName) { + return Parser.isA(test, testName || test.name); +} +const any = new Parser(new AnyParser()); +class ArrayOfParser { + constructor(parser, description = { + name: "ArrayOf", + children: [ + parser + ], + extras: [] + }){ + this.parser = parser; + this.description = description; + } + parse(a, onParse) { + if (!Array.isArray(a)) { + return onParse.invalid({ + value: a, + keys: [], + parser: this + }); + } + const values = [ + ...a + ]; + for(let index = 0; index < values.length; index++){ + const result = this.parser.enumParsed(values[index]); + if ("error" in result) { + result.error.keys.push("" + index); + return onParse.invalid(result.error); + } else { + values[index] = result.value; + } + } + return onParse.parsed(values); + } + parser; + description; +} +function arrayOf(validator) { + return new Parser(new ArrayOfParser(validator)); +} +const unknown = new Parser(new UnknownParser()); +const number = new Parser(new NumberParser()); +const isNill = new Parser(new NilParser()); +const natural = number.refine((x)=>x >= 0 && x === Math.floor(x)); +const isFunction = new Parser(new FunctionParser()); +const __boolean = new Parser(new BoolParser()); +class DeferredParser { + parser; + static create() { + return new DeferredParser(); + } + constructor(description = { + name: "Deferred", + children: [], + extras: [] + }){ + this.description = description; + } + setParser(parser) { + this.parser = new Parser(parser); + return this; + } + parse(a, onParse) { + if (!this.parser) { + return onParse.invalid({ + value: "Not Set Up", + keys: [], + parser: this + }); + } + return this.parser.parse(a, onParse); + } + description; +} +function deferred() { + const deferred = DeferredParser.create(); + function setParser(parser) { + deferred.setParser(parser); + } + return [ + new Parser(deferred), + setParser + ]; +} +const object = new Parser(new ObjectParser()); +class DictionaryParser { + constructor(parsers, description = { + name: "Dictionary", + children: parsers.reduce((acc, [k, v])=>{ + acc.push(k, v); + return acc; + }, []), + extras: [] + }){ + this.parsers = parsers; + this.description = description; + } + parse(a, onParse) { + const { parsers } = this; + const parser = this; + const answer = { + ...a + }; + outer: for(const key in a){ + let parseError = []; + for (const [keyParser, valueParser] of parsers){ + const enumState = keyParser.enumParsed(key); + if ("error" in enumState) { + const { error } = enumState; + error.parser = parser; + error.keys.push("" + key); + parseError.push(error); + continue; + } + const newKey = enumState.value; + const valueState = valueParser.enumParsed(a[key]); + if ("error" in valueState) { + const { error: error1 } = valueState; + error1.keys.push("" + newKey); + parseError.unshift(error1); + continue; + } + delete answer[key]; + answer[newKey] = valueState.value; + break outer; + } + const error2 = parseError[0]; + if (!!error2) { + return onParse.invalid(error2); + } + } + return onParse.parsed(answer); + } + parsers; + description; +} +const dictionary = (...parsers)=>{ + return object.concat(new DictionaryParser([ + ...parsers + ])); +}; +function every(...parsers) { + const filteredParsers = parsers.filter((x)=>x !== any); + if (filteredParsers.length <= 0) { + return any; + } + const first = filteredParsers.splice(0, 1)[0]; + return filteredParsers.reduce((left, right)=>{ + return left.concat(right); + }, first); +} +const isArray = new Parser(new ArrayParser()); +const string = new Parser(new StringParser()); +const instanceOf = (classCreator)=>guard((x)=>x instanceof classCreator, `is${classCreator.name}`); +class LiteralsParser { + constructor(values, description = { + name: "Literal", + children: [], + extras: values + }){ + this.values = values; + this.description = description; + } + parse(a, onParse) { + if (this.values.indexOf(a) >= 0) { + return onParse.parsed(a); + } + return onParse.invalid({ + value: a, + keys: [], + parser: this + }); + } + values; + description; +} +function literal(isEqualToValue) { + return new Parser(new LiteralsParser([ + isEqualToValue + ])); +} +function literals(firstValue, ...restValues) { + return new Parser(new LiteralsParser([ + firstValue, + ...restValues + ])); +} +class ShapeParser { + constructor(parserMap, isPartial, parserKeys = Object.keys(parserMap), description = { + name: isPartial ? "Partial" : "Shape", + children: parserKeys.map((key)=>parserMap[key]), + extras: parserKeys + }){ + this.parserMap = parserMap; + this.isPartial = isPartial; + this.parserKeys = parserKeys; + this.description = description; + } + parse(a, onParse) { + const parser = this; + if (!object.test(a)) { + return onParse.invalid({ + value: a, + keys: [], + parser + }); + } + const { parserMap , isPartial } = this; + const value = { + ...a + }; + if (Array.isArray(a)) { + value.length = a.length; + } + for(const key in parserMap){ + if (key in value) { + const parser1 = parserMap[key]; + const state = parser1.enumParsed(a[key]); + if ("error" in state) { + const { error } = state; + error.keys.push(saferStringify(key)); + return onParse.invalid(error); + } + const smallValue = state.value; + value[key] = smallValue; + } else if (!isPartial) { + return onParse.invalid({ + value: "missingProperty", + parser, + keys: [ + saferStringify(key) + ] + }); + } + } + return onParse.parsed(value); + } + parserMap; + isPartial; + parserKeys; + description; +} +const isPartial = (testShape)=>{ + return new Parser(new ShapeParser(testShape, true)); +}; +const partial = isPartial; +class RecursiveParser { + parser; + static create(fn) { + const parser = new RecursiveParser(fn); + parser.parser = fn(new Parser(parser)); + return parser; + } + constructor(recursive, description = { + name: "Recursive", + children: [], + extras: [ + recursive + ] + }){ + this.recursive = recursive; + this.description = description; + } + parse(a, onParse) { + if (!this.parser) { + return onParse.invalid({ + value: "Recursive Invalid State", + keys: [], + parser: this + }); + } + return this.parser.parse(a, onParse); + } + recursive; + description; +} +function recursive(fn) { + fn(any); + const created = RecursiveParser.create(fn); + return new Parser(created); +} +const regex = (tester)=>string.refine(function(x) { + return tester.test(x); + }, tester.toString()); +const isShape = (testShape)=>{ + return new Parser(new ShapeParser(testShape, false)); +}; +function shape(testShape, optionals, optionalAndDefaults) { + if (optionals) { + const defaults = optionalAndDefaults || {}; + console.log("test"); + const entries = Object.entries(testShape); + const optionalSet = new Set(Array.from(optionals)); + return every(partial(Object.fromEntries(entries.filter(([key, _])=>optionalSet.has(key)).map(([key, parser])=>[ + key, + parser + ]))), isShape(Object.fromEntries(entries.filter(([key, _])=>!optionalSet.has(key))))).map((ret)=>{ + for (const key of optionalSet){ + const keyAny = key; + if (!(keyAny in ret) && keyAny in defaults) { + ret[keyAny] = defaults[keyAny]; + } + } + return ret; + }); + } + return isShape(testShape); +} +function some(...parsers) { + if (parsers.length <= 0) { + return any; + } + const first = parsers.splice(0, 1)[0]; + return parsers.reduce((left, right)=>left.orParser(right), first); +} +class TupleParser { + constructor(parsers, lengthMatcher = literal(parsers.length), description = { + name: "Tuple", + children: parsers, + extras: [] + }){ + this.parsers = parsers; + this.lengthMatcher = lengthMatcher; + this.description = description; + } + parse(input, onParse) { + const tupleError = isArray.enumParsed(input); + if ("error" in tupleError) return onParse.invalid(tupleError.error); + const values = input; + const stateCheck = this.lengthMatcher.enumParsed(values.length); + if ("error" in stateCheck) { + stateCheck.error.keys.push(saferStringify("length")); + return onParse.invalid(stateCheck.error); + } + const answer = new Array(this.parsers.length); + for(const key in this.parsers){ + const parser = this.parsers[key]; + const value = values[key]; + const result = parser.enumParsed(value); + if ("error" in result) { + const { error } = result; + error.keys.push(saferStringify(key)); + return onParse.invalid(error); + } + answer[key] = result.value; + } + return onParse.parsed(answer); + } + parsers; + lengthMatcher; + description; +} +function tuple(...parsers) { + return new Parser(new TupleParser(parsers)); +} +class NamedParser { + constructor(parent, name, description = { + name: "Named", + children: [ + parent + ], + extras: [ + name + ] + }){ + this.parent = parent; + this.name = name; + this.description = description; + } + parse(a, onParse) { + const parser = this; + const parent = this.parent.enumParsed(a); + if ("error" in parent) { + const { error } = parent; + error.parser = parser; + return onParse.invalid(error); + } + return onParse.parsed(parent.value); + } + parent; + name; + description; +} +function parserName(name, parent) { + return new Parser(new NamedParser(parent, name)); +} +class Matched { + constructor(value){ + this.value = value; + } + when(..._args) { + return this; + } + defaultTo(_defaultValue) { + return this.value; + } + defaultToLazy(_getValue) { + return this.value; + } + unwrap() { + return this.value; + } + value; +} +class MatchMore { + constructor(a){ + this.a = a; + } + when(...args) { + const [outcome, ...matchers] = args.reverse(); + const me = this; + const parser = matches.some(...matchers.map((matcher)=>matcher instanceof Parser ? matcher : literal(matcher))); + const result = parser.enumParsed(this.a); + if ("error" in result) { + return me; + } + const { value } = result; + if (outcome instanceof Function) { + return new Matched(outcome(value)); + } + return new Matched(outcome); + } + defaultTo(value) { + return value; + } + defaultToLazy(getValue) { + return getValue(); + } + unwrap() { + throw new Error("Expecting that value is matched"); + } + a; +} +const matches = Object.assign(function matchesFn(value) { + return new MatchMore(value); +}, { + array: isArray, + arrayOf, + some, + tuple, + regex, + number, + natural, + isFunction, + object, + string, + shape, + partial, + literal, + every, + guard, + unknown, + any, + boolean: __boolean, + dictionary, + literals, + nill: isNill, + instanceOf, + Parse: Parser, + parserName, + recursive, + deferred +}); +class YAMLError extends Error { + constructor(message = "(unknown reason)", mark = ""){ + super(`${message} ${mark}`); + this.mark = mark; + this.name = this.constructor.name; + } + toString(_compact) { + return `${this.name}: ${this.message} ${this.mark}`; + } + mark; +} +function isBoolean(value) { + return typeof value === "boolean" || value instanceof Boolean; +} +function isObject1(value) { + return value !== null && typeof value === "object"; +} +function repeat(str, count) { + let result = ""; + for(let cycle = 0; cycle < count; cycle++){ + result += str; + } + return result; +} +function isNegativeZero(i) { + return i === 0 && Number.NEGATIVE_INFINITY === 1 / i; +} +class Mark { + constructor(name, buffer, position, line, column){ + this.name = name; + this.buffer = buffer; + this.position = position; + this.line = line; + this.column = column; + } + getSnippet(indent = 4, maxLength = 75) { + if (!this.buffer) return null; + let head = ""; + let start = this.position; + while(start > 0 && "\x00\r\n\x85\u2028\u2029".indexOf(this.buffer.charAt(start - 1)) === -1){ + start -= 1; + if (this.position - start > maxLength / 2 - 1) { + head = " ... "; + start += 5; + break; + } + } + let tail = ""; + let end = this.position; + while(end < this.buffer.length && "\x00\r\n\x85\u2028\u2029".indexOf(this.buffer.charAt(end)) === -1){ + end += 1; + if (end - this.position > maxLength / 2 - 1) { + tail = " ... "; + end -= 5; + break; + } + } + const snippet = this.buffer.slice(start, end); + return `${repeat(" ", indent)}${head}${snippet}${tail}\n${repeat(" ", indent + this.position - start + head.length)}^`; + } + toString(compact) { + let snippet, where = ""; + if (this.name) { + where += `in "${this.name}" `; + } + where += `at line ${this.line + 1}, column ${this.column + 1}`; + if (!compact) { + snippet = this.getSnippet(); + if (snippet) { + where += `:\n${snippet}`; + } + } + return where; + } + name; + buffer; + position; + line; + column; +} +function compileList(schema, name, result) { + const exclude = []; + for (const includedSchema of schema.include){ + result = compileList(includedSchema, name, result); + } + for (const currentType of schema[name]){ + for(let previousIndex = 0; previousIndex < result.length; previousIndex++){ + const previousType = result[previousIndex]; + if (previousType.tag === currentType.tag && previousType.kind === currentType.kind) { + exclude.push(previousIndex); + } + } + result.push(currentType); + } + return result.filter((_type, index)=>!exclude.includes(index)); +} +function compileMap(...typesList) { + const result = { + fallback: {}, + mapping: {}, + scalar: {}, + sequence: {} + }; + for (const types of typesList){ + for (const type of types){ + if (type.kind !== null) { + result[type.kind][type.tag] = result["fallback"][type.tag] = type; + } + } + } + return result; +} +class Schema { + static SCHEMA_DEFAULT; + implicit; + explicit; + include; + compiledImplicit; + compiledExplicit; + compiledTypeMap; + constructor(definition){ + this.explicit = definition.explicit || []; + this.implicit = definition.implicit || []; + this.include = definition.include || []; + for (const type of this.implicit){ + if (type.loadKind && type.loadKind !== "scalar") { + throw new YAMLError("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported."); + } + } + this.compiledImplicit = compileList(this, "implicit", []); + this.compiledExplicit = compileList(this, "explicit", []); + this.compiledTypeMap = compileMap(this.compiledImplicit, this.compiledExplicit); + } + extend(definition) { + return new Schema({ + implicit: [ + ...new Set([ + ...this.implicit, + ...definition?.implicit ?? [] + ]), + ], + explicit: [ + ...new Set([ + ...this.explicit, + ...definition?.explicit ?? [] + ]), + ], + include: [ + ...new Set([ + ...this.include, + ...definition?.include ?? [] + ]) + ] + }); + } + static create() {} +} +const DEFAULT_RESOLVE = ()=>true; +const DEFAULT_CONSTRUCT = (data)=>data; +function checkTagFormat(tag) { + return tag; +} +class Type { + tag; + kind = null; + instanceOf; + predicate; + represent; + defaultStyle; + styleAliases; + loadKind; + constructor(tag, options){ + this.tag = checkTagFormat(tag); + if (options) { + this.kind = options.kind; + this.resolve = options.resolve || DEFAULT_RESOLVE; + this.construct = options.construct || DEFAULT_CONSTRUCT; + this.instanceOf = options.instanceOf; + this.predicate = options.predicate; + this.represent = options.represent; + this.defaultStyle = options.defaultStyle; + this.styleAliases = options.styleAliases; + } + } + resolve = ()=>true; + construct = (data)=>data; +} +class DenoStdInternalError extends Error { + constructor(message){ + super(message); + this.name = "DenoStdInternalError"; + } +} +function assert(expr, msg = "") { + if (!expr) { + throw new DenoStdInternalError(msg); + } +} +function copy(src, dst, off = 0) { + off = Math.max(0, Math.min(off, dst.byteLength)); + const dstBytesAvailable = dst.byteLength - off; + if (src.byteLength > dstBytesAvailable) { + src = src.subarray(0, dstBytesAvailable); + } + dst.set(src, off); + return src.byteLength; +} +const MIN_READ = 32 * 1024; +const MAX_SIZE = 2 ** 32 - 2; +class Buffer { + #buf; + #off = 0; + constructor(ab){ + this.#buf = ab === undefined ? new Uint8Array(0) : new Uint8Array(ab); + } + bytes(options = { + copy: true + }) { + if (options.copy === false) return this.#buf.subarray(this.#off); + return this.#buf.slice(this.#off); + } + empty() { + return this.#buf.byteLength <= this.#off; + } + get length() { + return this.#buf.byteLength - this.#off; + } + get capacity() { + return this.#buf.buffer.byteLength; + } + truncate(n) { + if (n === 0) { + this.reset(); + return; + } + if (n < 0 || n > this.length) { + throw Error("bytes.Buffer: truncation out of range"); + } + this.#reslice(this.#off + n); + } + reset() { + this.#reslice(0); + this.#off = 0; + } + #tryGrowByReslice(n) { + const l = this.#buf.byteLength; + if (n <= this.capacity - l) { + this.#reslice(l + n); + return l; + } + return -1; + } + #reslice(len) { + assert(len <= this.#buf.buffer.byteLength); + this.#buf = new Uint8Array(this.#buf.buffer, 0, len); + } + readSync(p) { + if (this.empty()) { + this.reset(); + if (p.byteLength === 0) { + return 0; + } + return null; + } + const nread = copy(this.#buf.subarray(this.#off), p); + this.#off += nread; + return nread; + } + read(p) { + const rr = this.readSync(p); + return Promise.resolve(rr); + } + writeSync(p) { + const m = this.#grow(p.byteLength); + return copy(p, this.#buf, m); + } + write(p) { + const n = this.writeSync(p); + return Promise.resolve(n); + } + #grow(n1) { + const m = this.length; + if (m === 0 && this.#off !== 0) { + this.reset(); + } + const i = this.#tryGrowByReslice(n1); + if (i >= 0) { + return i; + } + const c = this.capacity; + if (n1 <= Math.floor(c / 2) - m) { + copy(this.#buf.subarray(this.#off), this.#buf); + } else if (c + n1 > MAX_SIZE) { + throw new Error("The buffer cannot be grown beyond the maximum size."); + } else { + const buf = new Uint8Array(Math.min(2 * c + n1, MAX_SIZE)); + copy(this.#buf.subarray(this.#off), buf); + this.#buf = buf; + } + this.#off = 0; + this.#reslice(Math.min(m + n1, MAX_SIZE)); + return m; + } + grow(n) { + if (n < 0) { + throw Error("Buffer.grow: negative count"); + } + const m = this.#grow(n); + this.#reslice(m); + } + async readFrom(r) { + let n = 0; + const tmp = new Uint8Array(MIN_READ); + while(true){ + const shouldGrow = this.capacity - this.length < MIN_READ; + const buf = shouldGrow ? tmp : new Uint8Array(this.#buf.buffer, this.length); + const nread = await r.read(buf); + if (nread === null) { + return n; + } + if (shouldGrow) this.writeSync(buf.subarray(0, nread)); + else this.#reslice(this.length + nread); + n += nread; + } + } + readFromSync(r) { + let n = 0; + const tmp = new Uint8Array(MIN_READ); + while(true){ + const shouldGrow = this.capacity - this.length < MIN_READ; + const buf = shouldGrow ? tmp : new Uint8Array(this.#buf.buffer, this.length); + const nread = r.readSync(buf); + if (nread === null) { + return n; + } + if (shouldGrow) this.writeSync(buf.subarray(0, nread)); + else this.#reslice(this.length + nread); + n += nread; + } + } +} +const MIN_BUF_SIZE = 16; +const CR = "\r".charCodeAt(0); +const LF = "\n".charCodeAt(0); +class BufferFullError extends Error { + name; + constructor(partial){ + super("Buffer full"); + this.partial = partial; + this.name = "BufferFullError"; + } + partial; +} +class PartialReadError extends Error { + name = "PartialReadError"; + partial; + constructor(){ + super("Encountered UnexpectedEof, data only partially read"); + } +} +class BufReader { + #buf; + #rd; + #r = 0; + #w = 0; + #eof = false; + static create(r, size = 4096) { + return r instanceof BufReader ? r : new BufReader(r, size); + } + constructor(rd, size = 4096){ + if (size < 16) { + size = MIN_BUF_SIZE; + } + this.#reset(new Uint8Array(size), rd); + } + size() { + return this.#buf.byteLength; + } + buffered() { + return this.#w - this.#r; + } + #fill = async ()=>{ + if (this.#r > 0) { + this.#buf.copyWithin(0, this.#r, this.#w); + this.#w -= this.#r; + this.#r = 0; + } + if (this.#w >= this.#buf.byteLength) { + throw Error("bufio: tried to fill full buffer"); + } + for(let i = 100; i > 0; i--){ + const rr = await this.#rd.read(this.#buf.subarray(this.#w)); + if (rr === null) { + this.#eof = true; + return; + } + assert(rr >= 0, "negative read"); + this.#w += rr; + if (rr > 0) { + return; + } + } + throw new Error(`No progress after ${100} read() calls`); + }; + reset(r) { + this.#reset(this.#buf, r); + } + #reset = (buf, rd)=>{ + this.#buf = buf; + this.#rd = rd; + this.#eof = false; + }; + async read(p) { + let rr = p.byteLength; + if (p.byteLength === 0) return rr; + if (this.#r === this.#w) { + if (p.byteLength >= this.#buf.byteLength) { + const rr1 = await this.#rd.read(p); + const nread = rr1 ?? 0; + assert(nread >= 0, "negative read"); + return rr1; + } + this.#r = 0; + this.#w = 0; + rr = await this.#rd.read(this.#buf); + if (rr === 0 || rr === null) return rr; + assert(rr >= 0, "negative read"); + this.#w += rr; + } + const copied = copy(this.#buf.subarray(this.#r, this.#w), p, 0); + this.#r += copied; + return copied; + } + async readFull(p) { + let bytesRead = 0; + while(bytesRead < p.length){ + try { + const rr = await this.read(p.subarray(bytesRead)); + if (rr === null) { + if (bytesRead === 0) { + return null; + } else { + throw new PartialReadError(); + } + } + bytesRead += rr; + } catch (err) { + if (err instanceof PartialReadError) { + err.partial = p.subarray(0, bytesRead); + } else if (err instanceof Error) { + const e = new PartialReadError(); + e.partial = p.subarray(0, bytesRead); + e.stack = err.stack; + e.message = err.message; + e.cause = err.cause; + throw err; + } + throw err; + } + } + return p; + } + async readByte() { + while(this.#r === this.#w){ + if (this.#eof) return null; + await this.#fill(); + } + const c = this.#buf[this.#r]; + this.#r++; + return c; + } + async readString(delim) { + if (delim.length !== 1) { + throw new Error("Delimiter should be a single character"); + } + const buffer = await this.readSlice(delim.charCodeAt(0)); + if (buffer === null) return null; + return new TextDecoder().decode(buffer); + } + async readLine() { + let line = null; + try { + line = await this.readSlice(LF); + } catch (err) { + if (err instanceof Deno.errors.BadResource) { + throw err; + } + let partial; + if (err instanceof PartialReadError) { + partial = err.partial; + assert(partial instanceof Uint8Array, "bufio: caught error from `readSlice()` without `partial` property"); + } + if (!(err instanceof BufferFullError)) { + throw err; + } + partial = err.partial; + if (!this.#eof && partial && partial.byteLength > 0 && partial[partial.byteLength - 1] === CR) { + assert(this.#r > 0, "bufio: tried to rewind past start of buffer"); + this.#r--; + partial = partial.subarray(0, partial.byteLength - 1); + } + if (partial) { + return { + line: partial, + more: !this.#eof + }; + } + } + if (line === null) { + return null; + } + if (line.byteLength === 0) { + return { + line, + more: false + }; + } + if (line[line.byteLength - 1] == LF) { + let drop = 1; + if (line.byteLength > 1 && line[line.byteLength - 2] === CR) { + drop = 2; + } + line = line.subarray(0, line.byteLength - drop); + } + return { + line, + more: false + }; + } + async readSlice(delim) { + let s = 0; + let slice; + while(true){ + let i = this.#buf.subarray(this.#r + s, this.#w).indexOf(delim); + if (i >= 0) { + i += s; + slice = this.#buf.subarray(this.#r, this.#r + i + 1); + this.#r += i + 1; + break; + } + if (this.#eof) { + if (this.#r === this.#w) { + return null; + } + slice = this.#buf.subarray(this.#r, this.#w); + this.#r = this.#w; + break; + } + if (this.buffered() >= this.#buf.byteLength) { + this.#r = this.#w; + const oldbuf = this.#buf; + const newbuf = this.#buf.slice(0); + this.#buf = newbuf; + throw new BufferFullError(oldbuf); + } + s = this.#w - this.#r; + try { + await this.#fill(); + } catch (err) { + if (err instanceof PartialReadError) { + err.partial = slice; + } else if (err instanceof Error) { + const e = new PartialReadError(); + e.partial = slice; + e.stack = err.stack; + e.message = err.message; + e.cause = err.cause; + throw err; + } + throw err; + } + } + return slice; + } + async peek(n) { + if (n < 0) { + throw Error("negative count"); + } + let avail = this.#w - this.#r; + while(avail < n && avail < this.#buf.byteLength && !this.#eof){ + try { + await this.#fill(); + } catch (err) { + if (err instanceof PartialReadError) { + err.partial = this.#buf.subarray(this.#r, this.#w); + } else if (err instanceof Error) { + const e = new PartialReadError(); + e.partial = this.#buf.subarray(this.#r, this.#w); + e.stack = err.stack; + e.message = err.message; + e.cause = err.cause; + throw err; + } + throw err; + } + avail = this.#w - this.#r; + } + if (avail === 0 && this.#eof) { + return null; + } else if (avail < n && this.#eof) { + return this.#buf.subarray(this.#r, this.#r + avail); + } else if (avail < n) { + throw new BufferFullError(this.#buf.subarray(this.#r, this.#w)); + } + return this.#buf.subarray(this.#r, this.#r + n); + } +} +class AbstractBufBase { + buf; + usedBufferBytes = 0; + err = null; + constructor(buf){ + this.buf = buf; + } + size() { + return this.buf.byteLength; + } + available() { + return this.buf.byteLength - this.usedBufferBytes; + } + buffered() { + return this.usedBufferBytes; + } +} +class BufWriter extends AbstractBufBase { + #writer; + static create(writer, size = 4096) { + return writer instanceof BufWriter ? writer : new BufWriter(writer, size); + } + constructor(writer, size = 4096){ + super(new Uint8Array(size <= 0 ? 4096 : size)); + this.#writer = writer; + } + reset(w) { + this.err = null; + this.usedBufferBytes = 0; + this.#writer = w; + } + async flush() { + if (this.err !== null) throw this.err; + if (this.usedBufferBytes === 0) return; + try { + const p = this.buf.subarray(0, this.usedBufferBytes); + let nwritten = 0; + while(nwritten < p.length){ + nwritten += await this.#writer.write(p.subarray(nwritten)); + } + } catch (e) { + if (e instanceof Error) { + this.err = e; + } + throw e; + } + this.buf = new Uint8Array(this.buf.length); + this.usedBufferBytes = 0; + } + async write(data) { + if (this.err !== null) throw this.err; + if (data.length === 0) return 0; + let totalBytesWritten = 0; + let numBytesWritten = 0; + while(data.byteLength > this.available()){ + if (this.buffered() === 0) { + try { + numBytesWritten = await this.#writer.write(data); + } catch (e) { + if (e instanceof Error) { + this.err = e; + } + throw e; + } + } else { + numBytesWritten = copy(data, this.buf, this.usedBufferBytes); + this.usedBufferBytes += numBytesWritten; + await this.flush(); + } + totalBytesWritten += numBytesWritten; + data = data.subarray(numBytesWritten); + } + numBytesWritten = copy(data, this.buf, this.usedBufferBytes); + this.usedBufferBytes += numBytesWritten; + totalBytesWritten += numBytesWritten; + return totalBytesWritten; + } +} +class BufWriterSync extends AbstractBufBase { + #writer; + static create(writer, size = 4096) { + return writer instanceof BufWriterSync ? writer : new BufWriterSync(writer, size); + } + constructor(writer, size = 4096){ + super(new Uint8Array(size <= 0 ? 4096 : size)); + this.#writer = writer; + } + reset(w) { + this.err = null; + this.usedBufferBytes = 0; + this.#writer = w; + } + flush() { + if (this.err !== null) throw this.err; + if (this.usedBufferBytes === 0) return; + try { + const p = this.buf.subarray(0, this.usedBufferBytes); + let nwritten = 0; + while(nwritten < p.length){ + nwritten += this.#writer.writeSync(p.subarray(nwritten)); + } + } catch (e) { + if (e instanceof Error) { + this.err = e; + } + throw e; + } + this.buf = new Uint8Array(this.buf.length); + this.usedBufferBytes = 0; + } + writeSync(data) { + if (this.err !== null) throw this.err; + if (data.length === 0) return 0; + let totalBytesWritten = 0; + let numBytesWritten = 0; + while(data.byteLength > this.available()){ + if (this.buffered() === 0) { + try { + numBytesWritten = this.#writer.writeSync(data); + } catch (e) { + if (e instanceof Error) { + this.err = e; + } + throw e; + } + } else { + numBytesWritten = copy(data, this.buf, this.usedBufferBytes); + this.usedBufferBytes += numBytesWritten; + this.flush(); + } + totalBytesWritten += numBytesWritten; + data = data.subarray(numBytesWritten); + } + numBytesWritten = copy(data, this.buf, this.usedBufferBytes); + this.usedBufferBytes += numBytesWritten; + totalBytesWritten += numBytesWritten; + return totalBytesWritten; + } +} +const BASE64_MAP = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r"; +function resolveYamlBinary(data) { + if (data === null) return false; + let code; + let bitlen = 0; + const max = data.length; + const map = BASE64_MAP; + for(let idx = 0; idx < max; idx++){ + code = map.indexOf(data.charAt(idx)); + if (code > 64) continue; + if (code < 0) return false; + bitlen += 6; + } + return bitlen % 8 === 0; +} +function constructYamlBinary(data) { + const input = data.replace(/[\r\n=]/g, ""); + const max = input.length; + const map = BASE64_MAP; + const result = []; + let bits = 0; + for(let idx = 0; idx < max; idx++){ + if (idx % 4 === 0 && idx) { + result.push(bits >> 16 & 0xff); + result.push(bits >> 8 & 0xff); + result.push(bits & 0xff); + } + bits = bits << 6 | map.indexOf(input.charAt(idx)); + } + const tailbits = max % 4 * 6; + if (tailbits === 0) { + result.push(bits >> 16 & 0xff); + result.push(bits >> 8 & 0xff); + result.push(bits & 0xff); + } else if (tailbits === 18) { + result.push(bits >> 10 & 0xff); + result.push(bits >> 2 & 0xff); + } else if (tailbits === 12) { + result.push(bits >> 4 & 0xff); + } + return new Buffer(new Uint8Array(result)); +} +function representYamlBinary(object) { + const max = object.length; + const map = BASE64_MAP; + let result = ""; + let bits = 0; + for(let idx = 0; idx < max; idx++){ + if (idx % 3 === 0 && idx) { + result += map[bits >> 18 & 0x3f]; + result += map[bits >> 12 & 0x3f]; + result += map[bits >> 6 & 0x3f]; + result += map[bits & 0x3f]; + } + bits = (bits << 8) + object[idx]; + } + const tail = max % 3; + if (tail === 0) { + result += map[bits >> 18 & 0x3f]; + result += map[bits >> 12 & 0x3f]; + result += map[bits >> 6 & 0x3f]; + result += map[bits & 0x3f]; + } else if (tail === 2) { + result += map[bits >> 10 & 0x3f]; + result += map[bits >> 4 & 0x3f]; + result += map[bits << 2 & 0x3f]; + result += map[64]; + } else if (tail === 1) { + result += map[bits >> 2 & 0x3f]; + result += map[bits << 4 & 0x3f]; + result += map[64]; + result += map[64]; + } + return result; +} +function isBinary(obj) { + const buf = new Buffer(); + try { + if (0 > buf.readFromSync(obj)) return true; + return false; + } catch { + return false; + } finally{ + buf.reset(); + } +} +const binary = new Type("tag:yaml.org,2002:binary", { + construct: constructYamlBinary, + kind: "scalar", + predicate: isBinary, + represent: representYamlBinary, + resolve: resolveYamlBinary +}); +function resolveYamlBoolean(data) { + const max = data.length; + return max === 4 && (data === "true" || data === "True" || data === "TRUE") || max === 5 && (data === "false" || data === "False" || data === "FALSE"); +} +function constructYamlBoolean(data) { + return data === "true" || data === "True" || data === "TRUE"; +} +const bool = new Type("tag:yaml.org,2002:bool", { + construct: constructYamlBoolean, + defaultStyle: "lowercase", + kind: "scalar", + predicate: isBoolean, + represent: { + lowercase (object) { + return object ? "true" : "false"; + }, + uppercase (object) { + return object ? "TRUE" : "FALSE"; + }, + camelcase (object) { + return object ? "True" : "False"; + } + }, + resolve: resolveYamlBoolean +}); +const YAML_FLOAT_PATTERN = new RegExp("^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?" + "|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?" + "|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*" + "|[-+]?\\.(?:inf|Inf|INF)" + "|\\.(?:nan|NaN|NAN))$"); +function resolveYamlFloat(data) { + if (!YAML_FLOAT_PATTERN.test(data) || data[data.length - 1] === "_") { + return false; + } + return true; +} +function constructYamlFloat(data) { + let value = data.replace(/_/g, "").toLowerCase(); + const sign = value[0] === "-" ? -1 : 1; + const digits = []; + if ("+-".indexOf(value[0]) >= 0) { + value = value.slice(1); + } + if (value === ".inf") { + return sign === 1 ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY; + } + if (value === ".nan") { + return NaN; + } + if (value.indexOf(":") >= 0) { + value.split(":").forEach((v)=>{ + digits.unshift(parseFloat(v)); + }); + let valueNb = 0.0; + let base = 1; + digits.forEach((d)=>{ + valueNb += d * base; + base *= 60; + }); + return sign * valueNb; + } + return sign * parseFloat(value); +} +const SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/; +function representYamlFloat(object, style) { + if (isNaN(object)) { + switch(style){ + case "lowercase": + return ".nan"; + case "uppercase": + return ".NAN"; + case "camelcase": + return ".NaN"; + } + } else if (Number.POSITIVE_INFINITY === object) { + switch(style){ + case "lowercase": + return ".inf"; + case "uppercase": + return ".INF"; + case "camelcase": + return ".Inf"; + } + } else if (Number.NEGATIVE_INFINITY === object) { + switch(style){ + case "lowercase": + return "-.inf"; + case "uppercase": + return "-.INF"; + case "camelcase": + return "-.Inf"; + } + } else if (isNegativeZero(object)) { + return "-0.0"; + } + const res = object.toString(10); + return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace("e", ".e") : res; +} +function isFloat(object) { + return Object.prototype.toString.call(object) === "[object Number]" && (object % 1 !== 0 || isNegativeZero(object)); +} +const __float = new Type("tag:yaml.org,2002:float", { + construct: constructYamlFloat, + defaultStyle: "lowercase", + kind: "scalar", + predicate: isFloat, + represent: representYamlFloat, + resolve: resolveYamlFloat +}); +function reconstructFunction(code) { + const func = new Function(`return ${code}`)(); + if (!(func instanceof Function)) { + throw new TypeError(`Expected function but got ${typeof func}: ${code}`); + } + return func; +} +new Type("tag:yaml.org,2002:js/function", { + kind: "scalar", + resolve (data) { + if (data === null) { + return false; + } + try { + reconstructFunction(`${data}`); + return true; + } catch (_err) { + return false; + } + }, + construct (data) { + return reconstructFunction(data); + }, + predicate (object) { + return object instanceof Function; + }, + represent (object) { + return object.toString(); + } +}); +function isHexCode(c) { + return 0x30 <= c && c <= 0x39 || 0x41 <= c && c <= 0x46 || 0x61 <= c && c <= 0x66; +} +function isOctCode(c) { + return 0x30 <= c && c <= 0x37; +} +function isDecCode(c) { + return 0x30 <= c && c <= 0x39; +} +function resolveYamlInteger(data) { + const max = data.length; + let index = 0; + let hasDigits = false; + if (!max) return false; + let ch = data[index]; + if (ch === "-" || ch === "+") { + ch = data[++index]; + } + if (ch === "0") { + if (index + 1 === max) return true; + ch = data[++index]; + if (ch === "b") { + index++; + for(; index < max; index++){ + ch = data[index]; + if (ch === "_") continue; + if (ch !== "0" && ch !== "1") return false; + hasDigits = true; + } + return hasDigits && ch !== "_"; + } + if (ch === "x") { + index++; + for(; index < max; index++){ + ch = data[index]; + if (ch === "_") continue; + if (!isHexCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && ch !== "_"; + } + for(; index < max; index++){ + ch = data[index]; + if (ch === "_") continue; + if (!isOctCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && ch !== "_"; + } + if (ch === "_") return false; + for(; index < max; index++){ + ch = data[index]; + if (ch === "_") continue; + if (ch === ":") break; + if (!isDecCode(data.charCodeAt(index))) { + return false; + } + hasDigits = true; + } + if (!hasDigits || ch === "_") return false; + if (ch !== ":") return true; + return /^(:[0-5]?[0-9])+$/.test(data.slice(index)); +} +function constructYamlInteger(data) { + let value = data; + const digits = []; + if (value.indexOf("_") !== -1) { + value = value.replace(/_/g, ""); + } + let sign = 1; + let ch = value[0]; + if (ch === "-" || ch === "+") { + if (ch === "-") sign = -1; + value = value.slice(1); + ch = value[0]; + } + if (value === "0") return 0; + if (ch === "0") { + if (value[1] === "b") return sign * parseInt(value.slice(2), 2); + if (value[1] === "x") return sign * parseInt(value, 16); + return sign * parseInt(value, 8); + } + if (value.indexOf(":") !== -1) { + value.split(":").forEach((v)=>{ + digits.unshift(parseInt(v, 10)); + }); + let valueInt = 0; + let base = 1; + digits.forEach((d)=>{ + valueInt += d * base; + base *= 60; + }); + return sign * valueInt; + } + return sign * parseInt(value, 10); +} +function isInteger(object) { + return Object.prototype.toString.call(object) === "[object Number]" && object % 1 === 0 && !isNegativeZero(object); +} +const __int = new Type("tag:yaml.org,2002:int", { + construct: constructYamlInteger, + defaultStyle: "decimal", + kind: "scalar", + predicate: isInteger, + represent: { + binary (obj) { + return obj >= 0 ? `0b${obj.toString(2)}` : `-0b${obj.toString(2).slice(1)}`; + }, + octal (obj) { + return obj >= 0 ? `0${obj.toString(8)}` : `-0${obj.toString(8).slice(1)}`; + }, + decimal (obj) { + return obj.toString(10); + }, + hexadecimal (obj) { + return obj >= 0 ? `0x${obj.toString(16).toUpperCase()}` : `-0x${obj.toString(16).toUpperCase().slice(1)}`; + } + }, + resolve: resolveYamlInteger, + styleAliases: { + binary: [ + 2, + "bin" + ], + decimal: [ + 10, + "dec" + ], + hexadecimal: [ + 16, + "hex" + ], + octal: [ + 8, + "oct" + ] + } +}); +const map = new Type("tag:yaml.org,2002:map", { + construct (data) { + return data !== null ? data : {}; + }, + kind: "mapping" +}); +function resolveYamlMerge(data) { + return data === "<<" || data === null; +} +const merge = new Type("tag:yaml.org,2002:merge", { + kind: "scalar", + resolve: resolveYamlMerge +}); +function resolveYamlNull(data) { + const max = data.length; + return max === 1 && data === "~" || max === 4 && (data === "null" || data === "Null" || data === "NULL"); +} +function constructYamlNull() { + return null; +} +function isNull(object) { + return object === null; +} +const nil = new Type("tag:yaml.org,2002:null", { + construct: constructYamlNull, + defaultStyle: "lowercase", + kind: "scalar", + predicate: isNull, + represent: { + canonical () { + return "~"; + }, + lowercase () { + return "null"; + }, + uppercase () { + return "NULL"; + }, + camelcase () { + return "Null"; + } + }, + resolve: resolveYamlNull +}); +const { hasOwn } = Object; +const _toString = Object.prototype.toString; +function resolveYamlOmap(data) { + const objectKeys = []; + let pairKey = ""; + let pairHasKey = false; + for (const pair of data){ + pairHasKey = false; + if (_toString.call(pair) !== "[object Object]") return false; + for(pairKey in pair){ + if (hasOwn(pair, pairKey)) { + if (!pairHasKey) pairHasKey = true; + else return false; + } + } + if (!pairHasKey) return false; + if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey); + else return false; + } + return true; +} +function constructYamlOmap(data) { + return data !== null ? data : []; +} +const omap = new Type("tag:yaml.org,2002:omap", { + construct: constructYamlOmap, + kind: "sequence", + resolve: resolveYamlOmap +}); +const _toString1 = Object.prototype.toString; +function resolveYamlPairs(data) { + const result = Array.from({ + length: data.length + }); + for(let index = 0; index < data.length; index++){ + const pair = data[index]; + if (_toString1.call(pair) !== "[object Object]") return false; + const keys = Object.keys(pair); + if (keys.length !== 1) return false; + result[index] = [ + keys[0], + pair[keys[0]] + ]; + } + return true; +} +function constructYamlPairs(data) { + if (data === null) return []; + const result = Array.from({ + length: data.length + }); + for(let index = 0; index < data.length; index += 1){ + const pair = data[index]; + const keys = Object.keys(pair); + result[index] = [ + keys[0], + pair[keys[0]] + ]; + } + return result; +} +const pairs = new Type("tag:yaml.org,2002:pairs", { + construct: constructYamlPairs, + kind: "sequence", + resolve: resolveYamlPairs +}); +const REGEXP = /^\/(?[\s\S]+)\/(?[gismuy]*)$/; +const regexp = new Type("tag:yaml.org,2002:js/regexp", { + kind: "scalar", + resolve (data) { + if (data === null || !data.length) { + return false; + } + const regexp = `${data}`; + if (regexp.charAt(0) === "/") { + if (!REGEXP.test(data)) { + return false; + } + const modifiers = [ + ...regexp.match(REGEXP)?.groups?.modifiers ?? "" + ]; + if (new Set(modifiers).size < modifiers.length) { + return false; + } + } + return true; + }, + construct (data) { + const { regexp =`${data}` , modifiers ="" } = `${data}`.match(REGEXP)?.groups ?? {}; + return new RegExp(regexp, modifiers); + }, + predicate (object) { + return object instanceof RegExp; + }, + represent (object) { + return object.toString(); + } +}); +const seq = new Type("tag:yaml.org,2002:seq", { + construct (data) { + return data !== null ? data : []; + }, + kind: "sequence" +}); +const { hasOwn: hasOwn1 } = Object; +function resolveYamlSet(data) { + if (data === null) return true; + for(const key in data){ + if (hasOwn1(data, key)) { + if (data[key] !== null) return false; + } + } + return true; +} +function constructYamlSet(data) { + return data !== null ? data : {}; +} +const set = new Type("tag:yaml.org,2002:set", { + construct: constructYamlSet, + kind: "mapping", + resolve: resolveYamlSet +}); +const str = new Type("tag:yaml.org,2002:str", { + construct (data) { + return data !== null ? data : ""; + }, + kind: "scalar" +}); +const YAML_DATE_REGEXP = new RegExp("^([0-9][0-9][0-9][0-9])" + "-([0-9][0-9])" + "-([0-9][0-9])$"); +const YAML_TIMESTAMP_REGEXP = new RegExp("^([0-9][0-9][0-9][0-9])" + "-([0-9][0-9]?)" + "-([0-9][0-9]?)" + "(?:[Tt]|[ \\t]+)" + "([0-9][0-9]?)" + ":([0-9][0-9])" + ":([0-9][0-9])" + "(?:\\.([0-9]*))?" + "(?:[ \\t]*(Z|([-+])([0-9][0-9]?)" + "(?::([0-9][0-9]))?))?$"); +function resolveYamlTimestamp(data) { + if (data === null) return false; + if (YAML_DATE_REGEXP.exec(data) !== null) return true; + if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true; + return false; +} +function constructYamlTimestamp(data) { + let match = YAML_DATE_REGEXP.exec(data); + if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data); + if (match === null) throw new Error("Date resolve error"); + const year = +match[1]; + const month = +match[2] - 1; + const day = +match[3]; + if (!match[4]) { + return new Date(Date.UTC(year, month, day)); + } + const hour = +match[4]; + const minute = +match[5]; + const second = +match[6]; + let fraction = 0; + if (match[7]) { + let partFraction = match[7].slice(0, 3); + while(partFraction.length < 3){ + partFraction += "0"; + } + fraction = +partFraction; + } + let delta = null; + if (match[9]) { + const tzHour = +match[10]; + const tzMinute = +(match[11] || 0); + delta = (tzHour * 60 + tzMinute) * 60000; + if (match[9] === "-") delta = -delta; + } + const date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction)); + if (delta) date.setTime(date.getTime() - delta); + return date; +} +function representYamlTimestamp(date) { + return date.toISOString(); +} +const timestamp = new Type("tag:yaml.org,2002:timestamp", { + construct: constructYamlTimestamp, + instanceOf: Date, + kind: "scalar", + represent: representYamlTimestamp, + resolve: resolveYamlTimestamp +}); +const undefinedType = new Type("tag:yaml.org,2002:js/undefined", { + kind: "scalar", + resolve () { + return true; + }, + construct () { + return undefined; + }, + predicate (object) { + return typeof object === "undefined"; + }, + represent () { + return ""; + } +}); +const failsafe = new Schema({ + explicit: [ + str, + seq, + map + ] +}); +const json = new Schema({ + implicit: [ + nil, + bool, + __int, + __float + ], + include: [ + failsafe + ] +}); +const core = new Schema({ + include: [ + json + ] +}); +const def = new Schema({ + explicit: [ + binary, + omap, + pairs, + set + ], + implicit: [ + timestamp, + merge + ], + include: [ + core + ] +}); +const extended = new Schema({ + explicit: [ + regexp, + undefinedType + ], + include: [ + def + ] +}); +class State { + constructor(schema = def){ + this.schema = schema; + } + schema; +} +class LoaderState extends State { + documents; + length; + lineIndent; + lineStart; + position; + line; + filename; + onWarning; + legacy; + json; + listener; + implicitTypes; + typeMap; + version; + checkLineBreaks; + tagMap; + anchorMap; + tag; + anchor; + kind; + result; + constructor(input, { filename , schema , onWarning , legacy =false , json =false , listener =null }){ + super(schema); + this.input = input; + this.documents = []; + this.lineIndent = 0; + this.lineStart = 0; + this.position = 0; + this.line = 0; + this.result = ""; + this.filename = filename; + this.onWarning = onWarning; + this.legacy = legacy; + this.json = json; + this.listener = listener; + this.implicitTypes = this.schema.compiledImplicit; + this.typeMap = this.schema.compiledTypeMap; + this.length = input.length; + } + input; +} +const { hasOwn: hasOwn2 } = Object; +const CONTEXT_BLOCK_IN = 3; +const CONTEXT_BLOCK_OUT = 4; +const CHOMPING_STRIP = 2; +const CHOMPING_KEEP = 3; +const PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; +const PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/; +const PATTERN_FLOW_INDICATORS = /[,\[\]\{\}]/; +const PATTERN_TAG_HANDLE = /^(?:!|!!|![a-z\-]+!)$/i; +const PATTERN_TAG_URI = /^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i; +function _class(obj) { + return Object.prototype.toString.call(obj); +} +function isEOL(c) { + return c === 0x0a || c === 0x0d; +} +function isWhiteSpace(c) { + return c === 0x09 || c === 0x20; +} +function isWsOrEol(c) { + return c === 0x09 || c === 0x20 || c === 0x0a || c === 0x0d; +} +function isFlowIndicator(c) { + return c === 0x2c || c === 0x5b || c === 0x5d || c === 0x7b || c === 0x7d; +} +function fromHexCode(c) { + if (0x30 <= c && c <= 0x39) { + return c - 0x30; + } + const lc = c | 0x20; + if (0x61 <= lc && lc <= 0x66) { + return lc - 0x61 + 10; + } + return -1; +} +function escapedHexLen(c) { + if (c === 0x78) { + return 2; + } + if (c === 0x75) { + return 4; + } + if (c === 0x55) { + return 8; + } + return 0; +} +function fromDecimalCode(c) { + if (0x30 <= c && c <= 0x39) { + return c - 0x30; + } + return -1; +} +function simpleEscapeSequence(c) { + return c === 0x30 ? "\x00" : c === 0x61 ? "\x07" : c === 0x62 ? "\x08" : c === 0x74 ? "\x09" : c === 0x09 ? "\x09" : c === 0x6e ? "\x0A" : c === 0x76 ? "\x0B" : c === 0x66 ? "\x0C" : c === 0x72 ? "\x0D" : c === 0x65 ? "\x1B" : c === 0x20 ? " " : c === 0x22 ? "\x22" : c === 0x2f ? "/" : c === 0x5c ? "\x5C" : c === 0x4e ? "\x85" : c === 0x5f ? "\xA0" : c === 0x4c ? "\u2028" : c === 0x50 ? "\u2029" : ""; +} +function charFromCodepoint(c) { + if (c <= 0xffff) { + return String.fromCharCode(c); + } + return String.fromCharCode((c - 0x010000 >> 10) + 0xd800, (c - 0x010000 & 0x03ff) + 0xdc00); +} +const simpleEscapeCheck = Array.from({ + length: 256 +}); +const simpleEscapeMap = Array.from({ + length: 256 +}); +for(let i1 = 0; i1 < 256; i1++){ + simpleEscapeCheck[i1] = simpleEscapeSequence(i1) ? 1 : 0; + simpleEscapeMap[i1] = simpleEscapeSequence(i1); +} +function generateError(state, message) { + return new YAMLError(message, new Mark(state.filename, state.input, state.position, state.line, state.position - state.lineStart)); +} +function throwError(state, message) { + throw generateError(state, message); +} +function throwWarning(state, message) { + if (state.onWarning) { + state.onWarning.call(null, generateError(state, message)); + } +} +const directiveHandlers = { + YAML (state, _name, ...args) { + if (state.version !== null) { + return throwError(state, "duplication of %YAML directive"); + } + if (args.length !== 1) { + return throwError(state, "YAML directive accepts exactly one argument"); + } + const match = /^([0-9]+)\.([0-9]+)$/.exec(args[0]); + if (match === null) { + return throwError(state, "ill-formed argument of the YAML directive"); + } + const major = parseInt(match[1], 10); + const minor = parseInt(match[2], 10); + if (major !== 1) { + return throwError(state, "unacceptable YAML version of the document"); + } + state.version = args[0]; + state.checkLineBreaks = minor < 2; + if (minor !== 1 && minor !== 2) { + return throwWarning(state, "unsupported YAML version of the document"); + } + }, + TAG (state, _name, ...args) { + if (args.length !== 2) { + return throwError(state, "TAG directive accepts exactly two arguments"); + } + const handle = args[0]; + const prefix = args[1]; + if (!PATTERN_TAG_HANDLE.test(handle)) { + return throwError(state, "ill-formed tag handle (first argument) of the TAG directive"); + } + if (state.tagMap && hasOwn2(state.tagMap, handle)) { + return throwError(state, `there is a previously declared suffix for "${handle}" tag handle`); + } + if (!PATTERN_TAG_URI.test(prefix)) { + return throwError(state, "ill-formed tag prefix (second argument) of the TAG directive"); + } + if (typeof state.tagMap === "undefined") { + state.tagMap = {}; + } + state.tagMap[handle] = prefix; + } +}; +function captureSegment(state, start, end, checkJson) { + let result; + if (start < end) { + result = state.input.slice(start, end); + if (checkJson) { + for(let position = 0, length = result.length; position < length; position++){ + const character = result.charCodeAt(position); + if (!(character === 0x09 || 0x20 <= character && character <= 0x10ffff)) { + return throwError(state, "expected valid JSON character"); + } + } + } else if (PATTERN_NON_PRINTABLE.test(result)) { + return throwError(state, "the stream contains non-printable characters"); + } + state.result += result; + } +} +function mergeMappings(state, destination, source, overridableKeys) { + if (!isObject1(source)) { + return throwError(state, "cannot merge mappings; the provided source object is unacceptable"); + } + const keys = Object.keys(source); + for(let i = 0, len = keys.length; i < len; i++){ + const key = keys[i]; + if (!hasOwn2(destination, key)) { + destination[key] = source[key]; + overridableKeys[key] = true; + } + } +} +function storeMappingPair(state, result, overridableKeys, keyTag, keyNode, valueNode, startLine, startPos) { + if (Array.isArray(keyNode)) { + keyNode = Array.prototype.slice.call(keyNode); + for(let index = 0, quantity = keyNode.length; index < quantity; index++){ + if (Array.isArray(keyNode[index])) { + return throwError(state, "nested arrays are not supported inside keys"); + } + if (typeof keyNode === "object" && _class(keyNode[index]) === "[object Object]") { + keyNode[index] = "[object Object]"; + } + } + } + if (typeof keyNode === "object" && _class(keyNode) === "[object Object]") { + keyNode = "[object Object]"; + } + keyNode = String(keyNode); + if (result === null) { + result = {}; + } + if (keyTag === "tag:yaml.org,2002:merge") { + if (Array.isArray(valueNode)) { + for(let index1 = 0, quantity1 = valueNode.length; index1 < quantity1; index1++){ + mergeMappings(state, result, valueNode[index1], overridableKeys); + } + } else { + mergeMappings(state, result, valueNode, overridableKeys); + } + } else { + if (!state.json && !hasOwn2(overridableKeys, keyNode) && hasOwn2(result, keyNode)) { + state.line = startLine || state.line; + state.position = startPos || state.position; + return throwError(state, "duplicated mapping key"); + } + result[keyNode] = valueNode; + delete overridableKeys[keyNode]; + } + return result; +} +function readLineBreak(state) { + const ch = state.input.charCodeAt(state.position); + if (ch === 0x0a) { + state.position++; + } else if (ch === 0x0d) { + state.position++; + if (state.input.charCodeAt(state.position) === 0x0a) { + state.position++; + } + } else { + return throwError(state, "a line break is expected"); + } + state.line += 1; + state.lineStart = state.position; +} +function skipSeparationSpace(state, allowComments, checkIndent) { + let lineBreaks = 0, ch = state.input.charCodeAt(state.position); + while(ch !== 0){ + while(isWhiteSpace(ch)){ + ch = state.input.charCodeAt(++state.position); + } + if (allowComments && ch === 0x23) { + do { + ch = state.input.charCodeAt(++state.position); + }while (ch !== 0x0a && ch !== 0x0d && ch !== 0) + } + if (isEOL(ch)) { + readLineBreak(state); + ch = state.input.charCodeAt(state.position); + lineBreaks++; + state.lineIndent = 0; + while(ch === 0x20){ + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + } else { + break; + } + } + if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) { + throwWarning(state, "deficient indentation"); + } + return lineBreaks; +} +function testDocumentSeparator(state) { + let _position = state.position; + let ch = state.input.charCodeAt(_position); + if ((ch === 0x2d || ch === 0x2e) && ch === state.input.charCodeAt(_position + 1) && ch === state.input.charCodeAt(_position + 2)) { + _position += 3; + ch = state.input.charCodeAt(_position); + if (ch === 0 || isWsOrEol(ch)) { + return true; + } + } + return false; +} +function writeFoldedLines(state, count) { + if (count === 1) { + state.result += " "; + } else if (count > 1) { + state.result += repeat("\n", count - 1); + } +} +function readPlainScalar(state, nodeIndent, withinFlowCollection) { + const kind = state.kind; + const result = state.result; + let ch = state.input.charCodeAt(state.position); + if (isWsOrEol(ch) || isFlowIndicator(ch) || ch === 0x23 || ch === 0x26 || ch === 0x2a || ch === 0x21 || ch === 0x7c || ch === 0x3e || ch === 0x27 || ch === 0x22 || ch === 0x25 || ch === 0x40 || ch === 0x60) { + return false; + } + let following; + if (ch === 0x3f || ch === 0x2d) { + following = state.input.charCodeAt(state.position + 1); + if (isWsOrEol(following) || withinFlowCollection && isFlowIndicator(following)) { + return false; + } + } + state.kind = "scalar"; + state.result = ""; + let captureEnd, captureStart = captureEnd = state.position; + let hasPendingContent = false; + let line = 0; + while(ch !== 0){ + if (ch === 0x3a) { + following = state.input.charCodeAt(state.position + 1); + if (isWsOrEol(following) || withinFlowCollection && isFlowIndicator(following)) { + break; + } + } else if (ch === 0x23) { + const preceding = state.input.charCodeAt(state.position - 1); + if (isWsOrEol(preceding)) { + break; + } + } else if (state.position === state.lineStart && testDocumentSeparator(state) || withinFlowCollection && isFlowIndicator(ch)) { + break; + } else if (isEOL(ch)) { + line = state.line; + const lineStart = state.lineStart; + const lineIndent = state.lineIndent; + skipSeparationSpace(state, false, -1); + if (state.lineIndent >= nodeIndent) { + hasPendingContent = true; + ch = state.input.charCodeAt(state.position); + continue; + } else { + state.position = captureEnd; + state.line = line; + state.lineStart = lineStart; + state.lineIndent = lineIndent; + break; + } + } + if (hasPendingContent) { + captureSegment(state, captureStart, captureEnd, false); + writeFoldedLines(state, state.line - line); + captureStart = captureEnd = state.position; + hasPendingContent = false; + } + if (!isWhiteSpace(ch)) { + captureEnd = state.position + 1; + } + ch = state.input.charCodeAt(++state.position); + } + captureSegment(state, captureStart, captureEnd, false); + if (state.result) { + return true; + } + state.kind = kind; + state.result = result; + return false; +} +function readSingleQuotedScalar(state, nodeIndent) { + let ch, captureStart, captureEnd; + ch = state.input.charCodeAt(state.position); + if (ch !== 0x27) { + return false; + } + state.kind = "scalar"; + state.result = ""; + state.position++; + captureStart = captureEnd = state.position; + while((ch = state.input.charCodeAt(state.position)) !== 0){ + if (ch === 0x27) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + if (ch === 0x27) { + captureStart = state.position; + state.position++; + captureEnd = state.position; + } else { + return true; + } + } else if (isEOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + return throwError(state, "unexpected end of the document within a single quoted scalar"); + } else { + state.position++; + captureEnd = state.position; + } + } + return throwError(state, "unexpected end of the stream within a single quoted scalar"); +} +function readDoubleQuotedScalar(state, nodeIndent) { + let ch = state.input.charCodeAt(state.position); + if (ch !== 0x22) { + return false; + } + state.kind = "scalar"; + state.result = ""; + state.position++; + let captureEnd, captureStart = captureEnd = state.position; + let tmp; + while((ch = state.input.charCodeAt(state.position)) !== 0){ + if (ch === 0x22) { + captureSegment(state, captureStart, state.position, true); + state.position++; + return true; + } + if (ch === 0x5c) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + if (isEOL(ch)) { + skipSeparationSpace(state, false, nodeIndent); + } else if (ch < 256 && simpleEscapeCheck[ch]) { + state.result += simpleEscapeMap[ch]; + state.position++; + } else if ((tmp = escapedHexLen(ch)) > 0) { + let hexLength = tmp; + let hexResult = 0; + for(; hexLength > 0; hexLength--){ + ch = state.input.charCodeAt(++state.position); + if ((tmp = fromHexCode(ch)) >= 0) { + hexResult = (hexResult << 4) + tmp; + } else { + return throwError(state, "expected hexadecimal character"); + } + } + state.result += charFromCodepoint(hexResult); + state.position++; + } else { + return throwError(state, "unknown escape sequence"); + } + captureStart = captureEnd = state.position; + } else if (isEOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + return throwError(state, "unexpected end of the document within a double quoted scalar"); + } else { + state.position++; + captureEnd = state.position; + } + } + return throwError(state, "unexpected end of the stream within a double quoted scalar"); +} +function readFlowCollection(state, nodeIndent) { + let ch = state.input.charCodeAt(state.position); + let terminator; + let isMapping = true; + let result = {}; + if (ch === 0x5b) { + terminator = 0x5d; + isMapping = false; + result = []; + } else if (ch === 0x7b) { + terminator = 0x7d; + } else { + return false; + } + if (state.anchor !== null && typeof state.anchor != "undefined" && typeof state.anchorMap != "undefined") { + state.anchorMap[state.anchor] = result; + } + ch = state.input.charCodeAt(++state.position); + const tag = state.tag, anchor = state.anchor; + let readNext = true; + let valueNode, keyNode, keyTag = keyNode = valueNode = null, isExplicitPair, isPair = isExplicitPair = false; + let following = 0, line = 0; + const overridableKeys = {}; + while(ch !== 0){ + skipSeparationSpace(state, true, nodeIndent); + ch = state.input.charCodeAt(state.position); + if (ch === terminator) { + state.position++; + state.tag = tag; + state.anchor = anchor; + state.kind = isMapping ? "mapping" : "sequence"; + state.result = result; + return true; + } + if (!readNext) { + return throwError(state, "missed comma between flow collection entries"); + } + keyTag = keyNode = valueNode = null; + isPair = isExplicitPair = false; + if (ch === 0x3f) { + following = state.input.charCodeAt(state.position + 1); + if (isWsOrEol(following)) { + isPair = isExplicitPair = true; + state.position++; + skipSeparationSpace(state, true, nodeIndent); + } + } + line = state.line; + composeNode(state, nodeIndent, 1, false, true); + keyTag = state.tag || null; + keyNode = state.result; + skipSeparationSpace(state, true, nodeIndent); + ch = state.input.charCodeAt(state.position); + if ((isExplicitPair || state.line === line) && ch === 0x3a) { + isPair = true; + ch = state.input.charCodeAt(++state.position); + skipSeparationSpace(state, true, nodeIndent); + composeNode(state, nodeIndent, 1, false, true); + valueNode = state.result; + } + if (isMapping) { + storeMappingPair(state, result, overridableKeys, keyTag, keyNode, valueNode); + } else if (isPair) { + result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode)); + } else { + result.push(keyNode); + } + skipSeparationSpace(state, true, nodeIndent); + ch = state.input.charCodeAt(state.position); + if (ch === 0x2c) { + readNext = true; + ch = state.input.charCodeAt(++state.position); + } else { + readNext = false; + } + } + return throwError(state, "unexpected end of the stream within a flow collection"); +} +function readBlockScalar(state, nodeIndent) { + let chomping = 1, didReadContent = false, detectedIndent = false, textIndent = nodeIndent, emptyLines = 0, atMoreIndented = false; + let ch = state.input.charCodeAt(state.position); + let folding = false; + if (ch === 0x7c) { + folding = false; + } else if (ch === 0x3e) { + folding = true; + } else { + return false; + } + state.kind = "scalar"; + state.result = ""; + let tmp = 0; + while(ch !== 0){ + ch = state.input.charCodeAt(++state.position); + if (ch === 0x2b || ch === 0x2d) { + if (1 === chomping) { + chomping = ch === 0x2b ? CHOMPING_KEEP : CHOMPING_STRIP; + } else { + return throwError(state, "repeat of a chomping mode identifier"); + } + } else if ((tmp = fromDecimalCode(ch)) >= 0) { + if (tmp === 0) { + return throwError(state, "bad explicit indentation width of a block scalar; it cannot be less than one"); + } else if (!detectedIndent) { + textIndent = nodeIndent + tmp - 1; + detectedIndent = true; + } else { + return throwError(state, "repeat of an indentation width identifier"); + } + } else { + break; + } + } + if (isWhiteSpace(ch)) { + do { + ch = state.input.charCodeAt(++state.position); + }while (isWhiteSpace(ch)) + if (ch === 0x23) { + do { + ch = state.input.charCodeAt(++state.position); + }while (!isEOL(ch) && ch !== 0) + } + } + while(ch !== 0){ + readLineBreak(state); + state.lineIndent = 0; + ch = state.input.charCodeAt(state.position); + while((!detectedIndent || state.lineIndent < textIndent) && ch === 0x20){ + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + if (!detectedIndent && state.lineIndent > textIndent) { + textIndent = state.lineIndent; + } + if (isEOL(ch)) { + emptyLines++; + continue; + } + if (state.lineIndent < textIndent) { + if (chomping === 3) { + state.result += repeat("\n", didReadContent ? 1 + emptyLines : emptyLines); + } else if (chomping === 1) { + if (didReadContent) { + state.result += "\n"; + } + } + break; + } + if (folding) { + if (isWhiteSpace(ch)) { + atMoreIndented = true; + state.result += repeat("\n", didReadContent ? 1 + emptyLines : emptyLines); + } else if (atMoreIndented) { + atMoreIndented = false; + state.result += repeat("\n", emptyLines + 1); + } else if (emptyLines === 0) { + if (didReadContent) { + state.result += " "; + } + } else { + state.result += repeat("\n", emptyLines); + } + } else { + state.result += repeat("\n", didReadContent ? 1 + emptyLines : emptyLines); + } + didReadContent = true; + detectedIndent = true; + emptyLines = 0; + const captureStart = state.position; + while(!isEOL(ch) && ch !== 0){ + ch = state.input.charCodeAt(++state.position); + } + captureSegment(state, captureStart, state.position, false); + } + return true; +} +function readBlockSequence(state, nodeIndent) { + let line, following, detected = false, ch; + const tag = state.tag, anchor = state.anchor, result = []; + if (state.anchor !== null && typeof state.anchor !== "undefined" && typeof state.anchorMap !== "undefined") { + state.anchorMap[state.anchor] = result; + } + ch = state.input.charCodeAt(state.position); + while(ch !== 0){ + if (ch !== 0x2d) { + break; + } + following = state.input.charCodeAt(state.position + 1); + if (!isWsOrEol(following)) { + break; + } + detected = true; + state.position++; + if (skipSeparationSpace(state, true, -1)) { + if (state.lineIndent <= nodeIndent) { + result.push(null); + ch = state.input.charCodeAt(state.position); + continue; + } + } + line = state.line; + composeNode(state, nodeIndent, 3, false, true); + result.push(state.result); + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + if ((state.line === line || state.lineIndent > nodeIndent) && ch !== 0) { + return throwError(state, "bad indentation of a sequence entry"); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + if (detected) { + state.tag = tag; + state.anchor = anchor; + state.kind = "sequence"; + state.result = result; + return true; + } + return false; +} +function readBlockMapping(state, nodeIndent, flowIndent) { + const tag = state.tag, anchor = state.anchor, result = {}, overridableKeys = {}; + let following, allowCompact = false, line, pos, keyTag = null, keyNode = null, valueNode = null, atExplicitKey = false, detected = false, ch; + if (state.anchor !== null && typeof state.anchor !== "undefined" && typeof state.anchorMap !== "undefined") { + state.anchorMap[state.anchor] = result; + } + ch = state.input.charCodeAt(state.position); + while(ch !== 0){ + following = state.input.charCodeAt(state.position + 1); + line = state.line; + pos = state.position; + if ((ch === 0x3f || ch === 0x3a) && isWsOrEol(following)) { + if (ch === 0x3f) { + if (atExplicitKey) { + storeMappingPair(state, result, overridableKeys, keyTag, keyNode, null); + keyTag = keyNode = valueNode = null; + } + detected = true; + atExplicitKey = true; + allowCompact = true; + } else if (atExplicitKey) { + atExplicitKey = false; + allowCompact = true; + } else { + return throwError(state, "incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line"); + } + state.position += 1; + ch = following; + } else if (composeNode(state, flowIndent, 2, false, true)) { + if (state.line === line) { + ch = state.input.charCodeAt(state.position); + while(isWhiteSpace(ch)){ + ch = state.input.charCodeAt(++state.position); + } + if (ch === 0x3a) { + ch = state.input.charCodeAt(++state.position); + if (!isWsOrEol(ch)) { + return throwError(state, "a whitespace character is expected after the key-value separator within a block mapping"); + } + if (atExplicitKey) { + storeMappingPair(state, result, overridableKeys, keyTag, keyNode, null); + keyTag = keyNode = valueNode = null; + } + detected = true; + atExplicitKey = false; + allowCompact = false; + keyTag = state.tag; + keyNode = state.result; + } else if (detected) { + return throwError(state, "can not read an implicit mapping pair; a colon is missed"); + } else { + state.tag = tag; + state.anchor = anchor; + return true; + } + } else if (detected) { + return throwError(state, "can not read a block mapping entry; a multiline key may not be an implicit key"); + } else { + state.tag = tag; + state.anchor = anchor; + return true; + } + } else { + break; + } + if (state.line === line || state.lineIndent > nodeIndent) { + if (composeNode(state, nodeIndent, 4, true, allowCompact)) { + if (atExplicitKey) { + keyNode = state.result; + } else { + valueNode = state.result; + } + } + if (!atExplicitKey) { + storeMappingPair(state, result, overridableKeys, keyTag, keyNode, valueNode, line, pos); + keyTag = keyNode = valueNode = null; + } + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + } + if (state.lineIndent > nodeIndent && ch !== 0) { + return throwError(state, "bad indentation of a mapping entry"); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + if (atExplicitKey) { + storeMappingPair(state, result, overridableKeys, keyTag, keyNode, null); + } + if (detected) { + state.tag = tag; + state.anchor = anchor; + state.kind = "mapping"; + state.result = result; + } + return detected; +} +function readTagProperty(state) { + let position, isVerbatim = false, isNamed = false, tagHandle = "", tagName, ch; + ch = state.input.charCodeAt(state.position); + if (ch !== 0x21) return false; + if (state.tag !== null) { + return throwError(state, "duplication of a tag property"); + } + ch = state.input.charCodeAt(++state.position); + if (ch === 0x3c) { + isVerbatim = true; + ch = state.input.charCodeAt(++state.position); + } else if (ch === 0x21) { + isNamed = true; + tagHandle = "!!"; + ch = state.input.charCodeAt(++state.position); + } else { + tagHandle = "!"; + } + position = state.position; + if (isVerbatim) { + do { + ch = state.input.charCodeAt(++state.position); + }while (ch !== 0 && ch !== 0x3e) + if (state.position < state.length) { + tagName = state.input.slice(position, state.position); + ch = state.input.charCodeAt(++state.position); + } else { + return throwError(state, "unexpected end of the stream within a verbatim tag"); + } + } else { + while(ch !== 0 && !isWsOrEol(ch)){ + if (ch === 0x21) { + if (!isNamed) { + tagHandle = state.input.slice(position - 1, state.position + 1); + if (!PATTERN_TAG_HANDLE.test(tagHandle)) { + return throwError(state, "named tag handle cannot contain such characters"); + } + isNamed = true; + position = state.position + 1; + } else { + return throwError(state, "tag suffix cannot contain exclamation marks"); + } + } + ch = state.input.charCodeAt(++state.position); + } + tagName = state.input.slice(position, state.position); + if (PATTERN_FLOW_INDICATORS.test(tagName)) { + return throwError(state, "tag suffix cannot contain flow indicator characters"); + } + } + if (tagName && !PATTERN_TAG_URI.test(tagName)) { + return throwError(state, `tag name cannot contain such characters: ${tagName}`); + } + if (isVerbatim) { + state.tag = tagName; + } else if (typeof state.tagMap !== "undefined" && hasOwn2(state.tagMap, tagHandle)) { + state.tag = state.tagMap[tagHandle] + tagName; + } else if (tagHandle === "!") { + state.tag = `!${tagName}`; + } else if (tagHandle === "!!") { + state.tag = `tag:yaml.org,2002:${tagName}`; + } else { + return throwError(state, `undeclared tag handle "${tagHandle}"`); + } + return true; +} +function readAnchorProperty(state) { + let ch = state.input.charCodeAt(state.position); + if (ch !== 0x26) return false; + if (state.anchor !== null) { + return throwError(state, "duplication of an anchor property"); + } + ch = state.input.charCodeAt(++state.position); + const position = state.position; + while(ch !== 0 && !isWsOrEol(ch) && !isFlowIndicator(ch)){ + ch = state.input.charCodeAt(++state.position); + } + if (state.position === position) { + return throwError(state, "name of an anchor node must contain at least one character"); + } + state.anchor = state.input.slice(position, state.position); + return true; +} +function readAlias(state) { + let ch = state.input.charCodeAt(state.position); + if (ch !== 0x2a) return false; + ch = state.input.charCodeAt(++state.position); + const _position = state.position; + while(ch !== 0 && !isWsOrEol(ch) && !isFlowIndicator(ch)){ + ch = state.input.charCodeAt(++state.position); + } + if (state.position === _position) { + return throwError(state, "name of an alias node must contain at least one character"); + } + const alias = state.input.slice(_position, state.position); + if (typeof state.anchorMap !== "undefined" && !hasOwn2(state.anchorMap, alias)) { + return throwError(state, `unidentified alias "${alias}"`); + } + if (typeof state.anchorMap !== "undefined") { + state.result = state.anchorMap[alias]; + } + skipSeparationSpace(state, true, -1); + return true; +} +function composeNode(state, parentIndent, nodeContext, allowToSeek, allowCompact) { + let allowBlockScalars, allowBlockCollections, indentStatus = 1, atNewLine = false, hasContent = false, type, flowIndent, blockIndent; + if (state.listener && state.listener !== null) { + state.listener("open", state); + } + state.tag = null; + state.anchor = null; + state.kind = null; + state.result = null; + const allowBlockStyles = allowBlockScalars = allowBlockCollections = CONTEXT_BLOCK_OUT === nodeContext || CONTEXT_BLOCK_IN === nodeContext; + if (allowToSeek) { + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true; + if (state.lineIndent > parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } + } + if (indentStatus === 1) { + while(readTagProperty(state) || readAnchorProperty(state)){ + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true; + allowBlockCollections = allowBlockStyles; + if (state.lineIndent > parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } else { + allowBlockCollections = false; + } + } + } + if (allowBlockCollections) { + allowBlockCollections = atNewLine || allowCompact; + } + if (indentStatus === 1 || 4 === nodeContext) { + const cond = 1 === nodeContext || 2 === nodeContext; + flowIndent = cond ? parentIndent : parentIndent + 1; + blockIndent = state.position - state.lineStart; + if (indentStatus === 1) { + if (allowBlockCollections && (readBlockSequence(state, blockIndent) || readBlockMapping(state, blockIndent, flowIndent)) || readFlowCollection(state, flowIndent)) { + hasContent = true; + } else { + if (allowBlockScalars && readBlockScalar(state, flowIndent) || readSingleQuotedScalar(state, flowIndent) || readDoubleQuotedScalar(state, flowIndent)) { + hasContent = true; + } else if (readAlias(state)) { + hasContent = true; + if (state.tag !== null || state.anchor !== null) { + return throwError(state, "alias node should not have Any properties"); + } + } else if (readPlainScalar(state, flowIndent, 1 === nodeContext)) { + hasContent = true; + if (state.tag === null) { + state.tag = "?"; + } + } + if (state.anchor !== null && typeof state.anchorMap !== "undefined") { + state.anchorMap[state.anchor] = state.result; + } + } + } else if (indentStatus === 0) { + hasContent = allowBlockCollections && readBlockSequence(state, blockIndent); + } + } + if (state.tag !== null && state.tag !== "!") { + if (state.tag === "?") { + for(let typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex++){ + type = state.implicitTypes[typeIndex]; + if (type.resolve(state.result)) { + state.result = type.construct(state.result); + state.tag = type.tag; + if (state.anchor !== null && typeof state.anchorMap !== "undefined") { + state.anchorMap[state.anchor] = state.result; + } + break; + } + } + } else if (hasOwn2(state.typeMap[state.kind || "fallback"], state.tag)) { + type = state.typeMap[state.kind || "fallback"][state.tag]; + if (state.result !== null && type.kind !== state.kind) { + return throwError(state, `unacceptable node kind for !<${state.tag}> tag; it should be "${type.kind}", not "${state.kind}"`); + } + if (!type.resolve(state.result)) { + return throwError(state, `cannot resolve a node with !<${state.tag}> explicit tag`); + } else { + state.result = type.construct(state.result); + if (state.anchor !== null && typeof state.anchorMap !== "undefined") { + state.anchorMap[state.anchor] = state.result; + } + } + } else { + return throwError(state, `unknown tag !<${state.tag}>`); + } + } + if (state.listener && state.listener !== null) { + state.listener("close", state); + } + return state.tag !== null || state.anchor !== null || hasContent; +} +function readDocument(state) { + const documentStart = state.position; + let position, directiveName, directiveArgs, hasDirectives = false, ch; + state.version = null; + state.checkLineBreaks = state.legacy; + state.tagMap = {}; + state.anchorMap = {}; + while((ch = state.input.charCodeAt(state.position)) !== 0){ + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + if (state.lineIndent > 0 || ch !== 0x25) { + break; + } + hasDirectives = true; + ch = state.input.charCodeAt(++state.position); + position = state.position; + while(ch !== 0 && !isWsOrEol(ch)){ + ch = state.input.charCodeAt(++state.position); + } + directiveName = state.input.slice(position, state.position); + directiveArgs = []; + if (directiveName.length < 1) { + return throwError(state, "directive name must not be less than one character in length"); + } + while(ch !== 0){ + while(isWhiteSpace(ch)){ + ch = state.input.charCodeAt(++state.position); + } + if (ch === 0x23) { + do { + ch = state.input.charCodeAt(++state.position); + }while (ch !== 0 && !isEOL(ch)) + break; + } + if (isEOL(ch)) break; + position = state.position; + while(ch !== 0 && !isWsOrEol(ch)){ + ch = state.input.charCodeAt(++state.position); + } + directiveArgs.push(state.input.slice(position, state.position)); + } + if (ch !== 0) readLineBreak(state); + if (hasOwn2(directiveHandlers, directiveName)) { + directiveHandlers[directiveName](state, directiveName, ...directiveArgs); + } else { + throwWarning(state, `unknown document directive "${directiveName}"`); + } + } + skipSeparationSpace(state, true, -1); + if (state.lineIndent === 0 && state.input.charCodeAt(state.position) === 0x2d && state.input.charCodeAt(state.position + 1) === 0x2d && state.input.charCodeAt(state.position + 2) === 0x2d) { + state.position += 3; + skipSeparationSpace(state, true, -1); + } else if (hasDirectives) { + return throwError(state, "directives end mark is expected"); + } + composeNode(state, state.lineIndent - 1, 4, false, true); + skipSeparationSpace(state, true, -1); + if (state.checkLineBreaks && PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) { + throwWarning(state, "non-ASCII line breaks are interpreted as content"); + } + state.documents.push(state.result); + if (state.position === state.lineStart && testDocumentSeparator(state)) { + if (state.input.charCodeAt(state.position) === 0x2e) { + state.position += 3; + skipSeparationSpace(state, true, -1); + } + return; + } + if (state.position < state.length - 1) { + return throwError(state, "end of the stream or a document separator is expected"); + } else { + return; + } +} +function loadDocuments(input, options) { + input = String(input); + options = options || {}; + if (input.length !== 0) { + if (input.charCodeAt(input.length - 1) !== 0x0a && input.charCodeAt(input.length - 1) !== 0x0d) { + input += "\n"; + } + if (input.charCodeAt(0) === 0xfeff) { + input = input.slice(1); + } + } + const state = new LoaderState(input, options); + state.input += "\0"; + while(state.input.charCodeAt(state.position) === 0x20){ + state.lineIndent += 1; + state.position += 1; + } + while(state.position < state.length - 1){ + readDocument(state); + } + return state.documents; +} +function isCbFunction(fn) { + return typeof fn === "function"; +} +function loadAll(input, iteratorOrOption, options) { + if (!isCbFunction(iteratorOrOption)) { + return loadDocuments(input, iteratorOrOption); + } + const documents = loadDocuments(input, options); + const iterator = iteratorOrOption; + for(let index = 0, length = documents.length; index < length; index++){ + iterator(documents[index]); + } + return void 0; +} +function load(input, options) { + const documents = loadDocuments(input, options); + if (documents.length === 0) { + return; + } + if (documents.length === 1) { + return documents[0]; + } + throw new YAMLError("expected a single document in the stream, but found more"); +} +function parse(content, options) { + return load(content, options); +} +function parseAll(content, iterator, options) { + return loadAll(content, iterator, options); +} +const { hasOwn: hasOwn3 } = Object; +function compileStyleMap(schema, map) { + if (typeof map === "undefined" || map === null) return {}; + let type; + const result = {}; + const keys = Object.keys(map); + let tag, style; + for(let index = 0, length = keys.length; index < length; index += 1){ + tag = keys[index]; + style = String(map[tag]); + if (tag.slice(0, 2) === "!!") { + tag = `tag:yaml.org,2002:${tag.slice(2)}`; + } + type = schema.compiledTypeMap.fallback[tag]; + if (type && typeof type.styleAliases !== "undefined" && hasOwn3(type.styleAliases, style)) { + style = type.styleAliases[style]; + } + result[tag] = style; + } + return result; +} +class DumperState extends State { + indent; + noArrayIndent; + skipInvalid; + flowLevel; + sortKeys; + lineWidth; + noRefs; + noCompatMode; + condenseFlow; + implicitTypes; + explicitTypes; + tag = null; + result = ""; + duplicates = []; + usedDuplicates = []; + styleMap; + dump; + constructor({ schema , indent =2 , noArrayIndent =false , skipInvalid =false , flowLevel =-1 , styles =null , sortKeys =false , lineWidth =80 , noRefs =false , noCompatMode =false , condenseFlow =false }){ + super(schema); + this.indent = Math.max(1, indent); + this.noArrayIndent = noArrayIndent; + this.skipInvalid = skipInvalid; + this.flowLevel = flowLevel; + this.styleMap = compileStyleMap(this.schema, styles); + this.sortKeys = sortKeys; + this.lineWidth = lineWidth; + this.noRefs = noRefs; + this.noCompatMode = noCompatMode; + this.condenseFlow = condenseFlow; + this.implicitTypes = this.schema.compiledImplicit; + this.explicitTypes = this.schema.compiledExplicit; + } +} +const _toString2 = Object.prototype.toString; +const { hasOwn: hasOwn4 } = Object; +const ESCAPE_SEQUENCES = {}; +ESCAPE_SEQUENCES[0x00] = "\\0"; +ESCAPE_SEQUENCES[0x07] = "\\a"; +ESCAPE_SEQUENCES[0x08] = "\\b"; +ESCAPE_SEQUENCES[0x09] = "\\t"; +ESCAPE_SEQUENCES[0x0a] = "\\n"; +ESCAPE_SEQUENCES[0x0b] = "\\v"; +ESCAPE_SEQUENCES[0x0c] = "\\f"; +ESCAPE_SEQUENCES[0x0d] = "\\r"; +ESCAPE_SEQUENCES[0x1b] = "\\e"; +ESCAPE_SEQUENCES[0x22] = '\\"'; +ESCAPE_SEQUENCES[0x5c] = "\\\\"; +ESCAPE_SEQUENCES[0x85] = "\\N"; +ESCAPE_SEQUENCES[0xa0] = "\\_"; +ESCAPE_SEQUENCES[0x2028] = "\\L"; +ESCAPE_SEQUENCES[0x2029] = "\\P"; +const DEPRECATED_BOOLEANS_SYNTAX = [ + "y", + "Y", + "yes", + "Yes", + "YES", + "on", + "On", + "ON", + "n", + "N", + "no", + "No", + "NO", + "off", + "Off", + "OFF", +]; +function encodeHex(character) { + const string = character.toString(16).toUpperCase(); + let handle; + let length; + if (character <= 0xff) { + handle = "x"; + length = 2; + } else if (character <= 0xffff) { + handle = "u"; + length = 4; + } else if (character <= 0xffffffff) { + handle = "U"; + length = 8; + } else { + throw new YAMLError("code point within a string may not be greater than 0xFFFFFFFF"); + } + return `\\${handle}${repeat("0", length - string.length)}${string}`; +} +function indentString(string, spaces) { + const ind = repeat(" ", spaces), length = string.length; + let position = 0, next = -1, result = "", line; + while(position < length){ + next = string.indexOf("\n", position); + if (next === -1) { + line = string.slice(position); + position = length; + } else { + line = string.slice(position, next + 1); + position = next + 1; + } + if (line.length && line !== "\n") result += ind; + result += line; + } + return result; +} +function generateNextLine(state, level) { + return `\n${repeat(" ", state.indent * level)}`; +} +function testImplicitResolving(state, str) { + let type; + for(let index = 0, length = state.implicitTypes.length; index < length; index += 1){ + type = state.implicitTypes[index]; + if (type.resolve(str)) { + return true; + } + } + return false; +} +function isWhitespace(c) { + return c === 0x20 || c === 0x09; +} +function isPrintable(c) { + return 0x00020 <= c && c <= 0x00007e || 0x000a1 <= c && c <= 0x00d7ff && c !== 0x2028 && c !== 0x2029 || 0x0e000 <= c && c <= 0x00fffd && c !== 0xfeff || 0x10000 <= c && c <= 0x10ffff; +} +function isPlainSafe(c) { + return isPrintable(c) && c !== 0xfeff && c !== 0x2c && c !== 0x5b && c !== 0x5d && c !== 0x7b && c !== 0x7d && c !== 0x3a && c !== 0x23; +} +function isPlainSafeFirst(c) { + return isPrintable(c) && c !== 0xfeff && !isWhitespace(c) && c !== 0x2d && c !== 0x3f && c !== 0x3a && c !== 0x2c && c !== 0x5b && c !== 0x5d && c !== 0x7b && c !== 0x7d && c !== 0x23 && c !== 0x26 && c !== 0x2a && c !== 0x21 && c !== 0x7c && c !== 0x3e && c !== 0x27 && c !== 0x22 && c !== 0x25 && c !== 0x40 && c !== 0x60; +} +function needIndentIndicator(string) { + const leadingSpaceRe = /^\n* /; + return leadingSpaceRe.test(string); +} +const STYLE_PLAIN = 1, STYLE_SINGLE = 2, STYLE_LITERAL = 3, STYLE_FOLDED = 4, STYLE_DOUBLE = 5; +function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, testAmbiguousType) { + const shouldTrackWidth = lineWidth !== -1; + let hasLineBreak = false, hasFoldableLine = false, previousLineBreak = -1, plain = isPlainSafeFirst(string.charCodeAt(0)) && !isWhitespace(string.charCodeAt(string.length - 1)); + let __char, i; + if (singleLineOnly) { + for(i = 0; i < string.length; i++){ + __char = string.charCodeAt(i); + if (!isPrintable(__char)) { + return 5; + } + plain = plain && isPlainSafe(__char); + } + } else { + for(i = 0; i < string.length; i++){ + __char = string.charCodeAt(i); + if (__char === 0x0a) { + hasLineBreak = true; + if (shouldTrackWidth) { + hasFoldableLine = hasFoldableLine || i - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1] !== " "; + previousLineBreak = i; + } + } else if (!isPrintable(__char)) { + return 5; + } + plain = plain && isPlainSafe(__char); + } + hasFoldableLine = hasFoldableLine || shouldTrackWidth && i - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1] !== " "; + } + if (!hasLineBreak && !hasFoldableLine) { + return plain && !testAmbiguousType(string) ? 1 : 2; + } + if (indentPerLevel > 9 && needIndentIndicator(string)) { + return 5; + } + return hasFoldableLine ? 4 : 3; +} +function foldLine(line, width) { + if (line === "" || line[0] === " ") return line; + const breakRe = / [^ ]/g; + let match; + let start = 0, end, curr = 0, next = 0; + let result = ""; + while(match = breakRe.exec(line)){ + next = match.index; + if (next - start > width) { + end = curr > start ? curr : next; + result += `\n${line.slice(start, end)}`; + start = end + 1; + } + curr = next; + } + result += "\n"; + if (line.length - start > width && curr > start) { + result += `${line.slice(start, curr)}\n${line.slice(curr + 1)}`; + } else { + result += line.slice(start); + } + return result.slice(1); +} +function dropEndingNewline(string) { + return string[string.length - 1] === "\n" ? string.slice(0, -1) : string; +} +function foldString(string, width) { + const lineRe = /(\n+)([^\n]*)/g; + let result = (()=>{ + let nextLF = string.indexOf("\n"); + nextLF = nextLF !== -1 ? nextLF : string.length; + lineRe.lastIndex = nextLF; + return foldLine(string.slice(0, nextLF), width); + })(); + let prevMoreIndented = string[0] === "\n" || string[0] === " "; + let moreIndented; + let match; + while(match = lineRe.exec(string)){ + const prefix = match[1], line = match[2]; + moreIndented = line[0] === " "; + result += prefix + (!prevMoreIndented && !moreIndented && line !== "" ? "\n" : "") + foldLine(line, width); + prevMoreIndented = moreIndented; + } + return result; +} +function escapeString(string) { + let result = ""; + let __char, nextChar; + let escapeSeq; + for(let i = 0; i < string.length; i++){ + __char = string.charCodeAt(i); + if (__char >= 0xd800 && __char <= 0xdbff) { + nextChar = string.charCodeAt(i + 1); + if (nextChar >= 0xdc00 && nextChar <= 0xdfff) { + result += encodeHex((__char - 0xd800) * 0x400 + nextChar - 0xdc00 + 0x10000); + i++; + continue; + } + } + escapeSeq = ESCAPE_SEQUENCES[__char]; + result += !escapeSeq && isPrintable(__char) ? string[i] : escapeSeq || encodeHex(__char); + } + return result; +} +function blockHeader(string, indentPerLevel) { + const indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : ""; + const clip = string[string.length - 1] === "\n"; + const keep = clip && (string[string.length - 2] === "\n" || string === "\n"); + const chomp = keep ? "+" : clip ? "" : "-"; + return `${indentIndicator}${chomp}\n`; +} +function writeScalar(state, string, level, iskey) { + state.dump = (()=>{ + if (string.length === 0) { + return "''"; + } + if (!state.noCompatMode && DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1) { + return `'${string}'`; + } + const indent = state.indent * Math.max(1, level); + const lineWidth = state.lineWidth === -1 ? -1 : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent); + const singleLineOnly = iskey || state.flowLevel > -1 && level >= state.flowLevel; + function testAmbiguity(str) { + return testImplicitResolving(state, str); + } + switch(chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth, testAmbiguity)){ + case STYLE_PLAIN: + return string; + case STYLE_SINGLE: + return `'${string.replace(/'/g, "''")}'`; + case STYLE_LITERAL: + return `|${blockHeader(string, state.indent)}${dropEndingNewline(indentString(string, indent))}`; + case STYLE_FOLDED: + return `>${blockHeader(string, state.indent)}${dropEndingNewline(indentString(foldString(string, lineWidth), indent))}`; + case STYLE_DOUBLE: + return `"${escapeString(string)}"`; + default: + throw new YAMLError("impossible error: invalid scalar style"); + } + })(); +} +function writeFlowSequence(state, level, object) { + let _result = ""; + const _tag = state.tag; + for(let index = 0, length = object.length; index < length; index += 1){ + if (writeNode(state, level, object[index], false, false)) { + if (index !== 0) _result += `,${!state.condenseFlow ? " " : ""}`; + _result += state.dump; + } + } + state.tag = _tag; + state.dump = `[${_result}]`; +} +function writeBlockSequence(state, level, object, compact = false) { + let _result = ""; + const _tag = state.tag; + for(let index = 0, length = object.length; index < length; index += 1){ + if (writeNode(state, level + 1, object[index], true, true)) { + if (!compact || index !== 0) { + _result += generateNextLine(state, level); + } + if (state.dump && 0x0a === state.dump.charCodeAt(0)) { + _result += "-"; + } else { + _result += "- "; + } + _result += state.dump; + } + } + state.tag = _tag; + state.dump = _result || "[]"; +} +function writeFlowMapping(state, level, object) { + let _result = ""; + const _tag = state.tag, objectKeyList = Object.keys(object); + let pairBuffer, objectKey, objectValue; + for(let index = 0, length = objectKeyList.length; index < length; index += 1){ + pairBuffer = state.condenseFlow ? '"' : ""; + if (index !== 0) pairBuffer += ", "; + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; + if (!writeNode(state, level, objectKey, false, false)) { + continue; + } + if (state.dump.length > 1024) pairBuffer += "? "; + pairBuffer += `${state.dump}${state.condenseFlow ? '"' : ""}:${state.condenseFlow ? "" : " "}`; + if (!writeNode(state, level, objectValue, false, false)) { + continue; + } + pairBuffer += state.dump; + _result += pairBuffer; + } + state.tag = _tag; + state.dump = `{${_result}}`; +} +function writeBlockMapping(state, level, object, compact = false) { + const _tag = state.tag, objectKeyList = Object.keys(object); + let _result = ""; + if (state.sortKeys === true) { + objectKeyList.sort(); + } else if (typeof state.sortKeys === "function") { + objectKeyList.sort(state.sortKeys); + } else if (state.sortKeys) { + throw new YAMLError("sortKeys must be a boolean or a function"); + } + let pairBuffer = "", objectKey, objectValue, explicitPair; + for(let index = 0, length = objectKeyList.length; index < length; index += 1){ + pairBuffer = ""; + if (!compact || index !== 0) { + pairBuffer += generateNextLine(state, level); + } + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; + if (!writeNode(state, level + 1, objectKey, true, true, true)) { + continue; + } + explicitPair = state.tag !== null && state.tag !== "?" || state.dump && state.dump.length > 1024; + if (explicitPair) { + if (state.dump && 0x0a === state.dump.charCodeAt(0)) { + pairBuffer += "?"; + } else { + pairBuffer += "? "; + } + } + pairBuffer += state.dump; + if (explicitPair) { + pairBuffer += generateNextLine(state, level); + } + if (!writeNode(state, level + 1, objectValue, true, explicitPair)) { + continue; + } + if (state.dump && 0x0a === state.dump.charCodeAt(0)) { + pairBuffer += ":"; + } else { + pairBuffer += ": "; + } + pairBuffer += state.dump; + _result += pairBuffer; + } + state.tag = _tag; + state.dump = _result || "{}"; +} +function detectType(state, object, explicit = false) { + const typeList = explicit ? state.explicitTypes : state.implicitTypes; + let type; + let style; + let _result; + for(let index = 0, length = typeList.length; index < length; index += 1){ + type = typeList[index]; + if ((type.instanceOf || type.predicate) && (!type.instanceOf || typeof object === "object" && object instanceof type.instanceOf) && (!type.predicate || type.predicate(object))) { + state.tag = explicit ? type.tag : "?"; + if (type.represent) { + style = state.styleMap[type.tag] || type.defaultStyle; + if (_toString2.call(type.represent) === "[object Function]") { + _result = type.represent(object, style); + } else if (hasOwn4(type.represent, style)) { + _result = type.represent[style](object, style); + } else { + throw new YAMLError(`!<${type.tag}> tag resolver accepts not "${style}" style`); + } + state.dump = _result; + } + return true; + } + } + return false; +} +function writeNode(state, level, object, block, compact, iskey = false) { + state.tag = null; + state.dump = object; + if (!detectType(state, object, false)) { + detectType(state, object, true); + } + const type = _toString2.call(state.dump); + if (block) { + block = state.flowLevel < 0 || state.flowLevel > level; + } + const objectOrArray = type === "[object Object]" || type === "[object Array]"; + let duplicateIndex = -1; + let duplicate = false; + if (objectOrArray) { + duplicateIndex = state.duplicates.indexOf(object); + duplicate = duplicateIndex !== -1; + } + if (state.tag !== null && state.tag !== "?" || duplicate || state.indent !== 2 && level > 0) { + compact = false; + } + if (duplicate && state.usedDuplicates[duplicateIndex]) { + state.dump = `*ref_${duplicateIndex}`; + } else { + if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) { + state.usedDuplicates[duplicateIndex] = true; + } + if (type === "[object Object]") { + if (block && Object.keys(state.dump).length !== 0) { + writeBlockMapping(state, level, state.dump, compact); + if (duplicate) { + state.dump = `&ref_${duplicateIndex}${state.dump}`; + } + } else { + writeFlowMapping(state, level, state.dump); + if (duplicate) { + state.dump = `&ref_${duplicateIndex} ${state.dump}`; + } + } + } else if (type === "[object Array]") { + const arrayLevel = state.noArrayIndent && level > 0 ? level - 1 : level; + if (block && state.dump.length !== 0) { + writeBlockSequence(state, arrayLevel, state.dump, compact); + if (duplicate) { + state.dump = `&ref_${duplicateIndex}${state.dump}`; + } + } else { + writeFlowSequence(state, arrayLevel, state.dump); + if (duplicate) { + state.dump = `&ref_${duplicateIndex} ${state.dump}`; + } + } + } else if (type === "[object String]") { + if (state.tag !== "?") { + writeScalar(state, state.dump, level, iskey); + } + } else { + if (state.skipInvalid) return false; + throw new YAMLError(`unacceptable kind of an object to dump ${type}`); + } + if (state.tag !== null && state.tag !== "?") { + state.dump = `!<${state.tag}> ${state.dump}`; + } + } + return true; +} +function inspectNode(object, objects, duplicatesIndexes) { + if (object !== null && typeof object === "object") { + const index = objects.indexOf(object); + if (index !== -1) { + if (duplicatesIndexes.indexOf(index) === -1) { + duplicatesIndexes.push(index); + } + } else { + objects.push(object); + if (Array.isArray(object)) { + for(let idx = 0, length = object.length; idx < length; idx += 1){ + inspectNode(object[idx], objects, duplicatesIndexes); + } + } else { + const objectKeyList = Object.keys(object); + for(let idx1 = 0, length1 = objectKeyList.length; idx1 < length1; idx1 += 1){ + inspectNode(object[objectKeyList[idx1]], objects, duplicatesIndexes); + } + } + } + } +} +function getDuplicateReferences(object, state) { + const objects = [], duplicatesIndexes = []; + inspectNode(object, objects, duplicatesIndexes); + const length = duplicatesIndexes.length; + for(let index = 0; index < length; index += 1){ + state.duplicates.push(objects[duplicatesIndexes[index]]); + } + state.usedDuplicates = Array.from({ + length + }); +} +function dump(input, options) { + options = options || {}; + const state = new DumperState(options); + if (!state.noRefs) getDuplicateReferences(input, state); + if (writeNode(state, 0, input, true, true)) return `${state.dump}\n`; + return ""; +} +function stringify(obj, options) { + return dump(obj, options); +} +const mod = { + parse: parse, + parseAll: parseAll, + stringify: stringify, + Type: Type, + CORE_SCHEMA: core, + DEFAULT_SCHEMA: def, + EXTENDED_SCHEMA: extended, + FAILSAFE_SCHEMA: failsafe, + JSON_SCHEMA: json +}; +const { number: number1 } = matches; +const setConfig = async (effects, newConfig)=>{ + await effects.createDir({ + path: "start9", + volumeId: "main" + }); + await effects.writeFile({ + path: "start9/config.yaml", + toWrite: mod.stringify(newConfig), + volumeId: "main" + }); + const dependsOnElectrs = !!newConfig?.['enable-electrs'] ? { + electrs: [ + 'synced' + ] + } : {}; + const dependsOnBitcoind = !!newConfig?.txindex ? { + bitcoind: [] + } : {}; + const result = { + signal: "SIGTERM", + "depends-on": { + ...dependsOnElectrs, + ...dependsOnBitcoind + } + }; + return { + result + }; +}; +const properties = async (effects)=>{ + return { + result: mod.parse(await effects.readFile({ + path: "start9/stats.yaml", + volumeId: "main" + })) + }; +}; +const { any: any1 , string: string1 , dictionary: dictionary1 } = matches; +const matchConfig = dictionary1([ + string1, + any1 +]); +const getConfig = async (effects)=>{ + const config = await effects.readFile({ + path: "start9/config.yaml", + volumeId: "main" + }).then((x)=>mod.parse(x)).then((x)=>matchConfig.unsafeCast(x)).catch((e)=>{ + effects.warn(`Got error ${e} while trying to read the config`); + return undefined; + }); + const spec = { + "tor-address": { + "name": "Tor Address", + "description": "The Tor address of the network interface", + "type": "pointer", + "subtype": "package", + "package-id": "mempool", + "target": "tor-address", + "interface": "main" + }, + "bitcoind": { + "type": "union", + "name": "Bitcoin Core", + "description": "The Bitcoin Core node to connect to:\n - internal: The Bitcoin Core or Proxy services installed to your Embassy\n", + "tag": { + "id": "type", + "name": "Type", + "variant-names": { + "internal": "Bitcoin Core", + "internal-proxy": "Bitcoin Proxy" + }, + "description": "The Bitcoin Core node to connect to:\n - internal: The Bitcoin Core and Proxy services installed to your Embassy\n" + }, + "default": "internal-proxy", + "variants": { + "internal": { + "user": { + "type": "pointer", + "name": "RPC Username", + "description": "The username for Bitcoin Core's RPC interface", + "subtype": "package", + "package-id": "bitcoind", + "target": "config", + "multi": false, + "selector": "$.rpc.username" + }, + "password": { + "type": "pointer", + "name": "RPC Password", + "description": "The password for Bitcoin Core's RPC interface", + "subtype": "package", + "package-id": "bitcoind", + "target": "config", + "multi": false, + "selector": "$.rpc.password" + } + }, + "internal-proxy": { + "user": { + "type": "pointer", + "name": "RPC Username", + "description": "The username for the RPC user allocated to electrs", + "subtype": "package", + "package-id": "btc-rpc-proxy", + "target": "config", + "multi": false, + "selector": "$.users[?(@.name == \"mempool\")].name" + }, + "password": { + "type": "pointer", + "name": "RPC Password", + "description": "The password for the RPC user allocated to electrs", + "subtype": "package", + "package-id": "btc-rpc-proxy", + "target": "config", + "multi": false, + "selector": "$.users[?(@.name == \"mempool\")].password" + }, + "txindex": { + "name": "Transaction Indexer", + "description": "The Transaction Indexer for Bitcoin Core", + "type": "pointer", + "subtype": "package", + "package-id": "bitcoind", + "target": "config", + "multi": false, + "selector": "$.txindex" + } + } + } + }, + "enable-electrs": { + "name": "Enable Electrs Address Lookups", + "description": "Enables address lookups via an internal electrs instance", + "type": "boolean", + "default": true + } + }; + return { + result: { + config, + spec + } + }; +}; +const { shape: shape1 , arrayOf: arrayOf1 , string: string2 , boolean: __boolean1 } = matches; +const matchBitcoindConfig = shape1({ + advanced: shape1({ + pruning: shape1({ + mode: string2 + }) + }), + rpc: shape1({ + enable: __boolean1 + }), + txindex: __boolean1 +}); +const matchProxyConfig = shape1({ + users: arrayOf1(shape1({ + name: string2, + "allowed-calls": arrayOf1(string2), + password: string2 + })) +}); +function times(fn, amount) { + const answer = new Array(amount); + for(let i = 0; i < amount; i++){ + answer[i] = fn(i); + } + return answer; +} +function randomItemString(input) { + return input[Math.floor(Math.random() * input.length)]; +} +const serviceName = "mempool"; +const fullChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +const proxyChecks = [ + { + currentError (config) { + if (!matchProxyConfig.test(config)) { + return "Config is not the correct shape"; + } + if (config.users.some((x)=>x.name === serviceName)) { + return; + } + return `Must have an RPC user named "${serviceName}"`; + }, + fix (config) { + config.users.push({ + name: serviceName, + "allowed-calls": [], + password: times(()=>randomItemString(fullChars), 22).join("") + }); + } + }, + ...[ + "echo", + "getindexinfo", + "getblockcount", + "getchaintips", + "getmempoolinfo", + "getblockchaininfo", + "getblockhash", + "getblock", + "getmempoolentry", + "getrawtransaction", + "getrawmempool", + "gettxout", + "validateaddress", + "getblockstats", + "getnetworkhashps", + "getdifficulty", + ].map((operator)=>({ + currentError (config) { + if (!matchProxyConfig.test(config)) { + return "Config is not the correct shape"; + } + if (config.users.find((x)=>x.name === serviceName)?.["allowed-calls"]?.some((x)=>x === operator) ?? false) { + return; + } + return `RPC user "mempool" must have "${operator}" enabled`; + }, + fix (config) { + if (!matchProxyConfig.test(config)) { + throw new Error("Config is not the correct shape"); + } + const found = config.users.find((x)=>x.name === serviceName); + if (!found) { + throw new Error("Users for mempool should exist"); + } + found["allowed-calls"] = [ + ...found["allowed-calls"] ?? [], + operator + ]; + } + })), +]; +const dependencies = { + bitcoind: { + async check (effects, configInput) { + effects.info("check bitcoind"); + const config = matchBitcoindConfig.unsafeCast(configInput); + if (!config.rpc.enable) { + return { + error: 'Must have RPC enabled' + }; + } + if (!config.txindex) { + return { + error: 'Must have transaction indexing enabled' + }; + } + if (config.advanced.pruning.mode == "enabled") { + return { + error: 'Pruning must be disabled to use Bitcoin Core directly. To use with a pruned node, set Bitcoin Core to Bitcoin Proxy instead.' + }; + } + return { + result: null + }; + }, + async autoConfigure (effects, configInput) { + effects.info("autoconfigure bitcoind"); + const config = matchBitcoindConfig.unsafeCast(configInput); + config.rpc.enable = true; + config.txindex = true; + config.advanced.pruning.mode = "disabled"; + return { + result: config + }; + } + }, + "btc-rpc-proxy": { + async check (effects, configInput) { + effects.info("check btc-rpc-proxy"); + for (const checker of proxyChecks){ + const error = checker.currentError(configInput); + if (error) { + effects.error(`throwing error: ${error}`); + return { + error + }; + } + } + return { + result: null + }; + }, + async autoConfigure (effects, configInput) { + effects.info("autoconfigure btc-rpc-proxy"); + for (const checker of proxyChecks){ + const error = checker.currentError(configInput); + if (error) { + checker.fix(configInput); + } + } + return { + result: configInput + }; + } + } +}; +export { setConfig as setConfig }; +export { properties as properties }; +export { getConfig as getConfig }; +export { dependencies as dependencies }; diff --git a/scripts/embassy.ts b/scripts/embassy.ts new file mode 100644 index 0000000..9165741 --- /dev/null +++ b/scripts/embassy.ts @@ -0,0 +1,4 @@ +export { setConfig } from "./services/setConfig.ts"; +export { properties } from "./services/properties.ts"; +export { getConfig } from "./services/getConfig.ts"; +export { dependencies } from "./services/dependencies.ts"; \ No newline at end of file diff --git a/scripts/services/dependencies.ts b/scripts/services/dependencies.ts new file mode 100644 index 0000000..d4b36cd --- /dev/null +++ b/scripts/services/dependencies.ts @@ -0,0 +1,157 @@ +import { ExpectedExports, Config, matches } from "../deps.ts"; + +const { shape, arrayOf, string, boolean } = matches; + +const matchBitcoindConfig = shape({ + advanced: shape({ + pruning: shape({ + mode: string, + }), + }), + rpc: shape({ + enable: boolean, + }), + txindex: boolean, +}); + +const matchProxyConfig = shape({ + users: arrayOf( + shape( + { + name: string, + "allowed-calls": arrayOf(string), + password: string, + }, + ) + ), +}); + +function times(fn: (i: number) => T, amount: number): T[] { + const answer = new Array(amount); + for (let i = 0; i < amount; i++) { + answer[i] = fn(i); + } + return answer; +} + +function randomItemString(input: string) { + return input[Math.floor(Math.random() * input.length)]; +} + +const serviceName = "mempool"; +const fullChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +type Check = { + currentError(config: Config): string | void; + fix(config: Config): void; +}; + +const proxyChecks: Array = [ + { + currentError(config) { + if (!matchProxyConfig.test(config)) { + return "Config is not the correct shape"; + } + if (config.users.some((x) => x.name === serviceName)) { + return; + } + return `Must have an RPC user named "${serviceName}"`; + }, + fix(config) { + config.users.push({ + name: serviceName, + "allowed-calls": [], + password: times(() => randomItemString(fullChars), 22).join(""), + }); + }, + }, + ...[ + "echo", + "getindexinfo", + "getblockcount", + "getchaintips", + "getmempoolinfo", + "getblockchaininfo", + "getblockhash", + "getblock", + "getmempoolentry", + "getrawtransaction", + "getrawmempool", + "gettxout", + "validateaddress", + "getblockstats", + "getnetworkhashps", + "getdifficulty", + ].map( + (operator): Check => ({ + currentError(config) { + if (!matchProxyConfig.test(config)) { + return "Config is not the correct shape"; + } + if (config.users.find((x) => x.name === serviceName)?.["allowed-calls"]?.some((x) => x === operator) ?? false) { + return; + } + return `RPC user "mempool" must have "${operator}" enabled`; + }, + fix(config) { + if (!matchProxyConfig.test(config)) { + throw new Error("Config is not the correct shape"); + } + const found = config.users.find((x) => x.name === serviceName); + if (!found) { + throw new Error("Users for mempool should exist"); + } + found["allowed-calls"] = [...(found["allowed-calls"] ?? []), operator]; + }, + }) + ), +]; + +export const dependencies: ExpectedExports.dependencies = { + bitcoind: { + async check(effects, configInput) { + effects.info("check bitcoind"); + const config = matchBitcoindConfig.unsafeCast(configInput); + if (!config.rpc.enable) { + return { error: 'Must have RPC enabled' }; + } + if (!config.txindex) { + return { error: 'Must have transaction indexing enabled' }; + } + if (config.advanced.pruning.mode=="enabled") { + return { error: 'Pruning must be disabled to use Bitcoin Core directly. To use with a pruned node, set Bitcoin Core to Bitcoin Proxy instead.' }; + } + return { result: null }; + }, + async autoConfigure(effects, configInput) { + effects.info("autoconfigure bitcoind"); + const config = matchBitcoindConfig.unsafeCast(configInput); + config.rpc.enable = true; + config.txindex = true; + config.advanced.pruning.mode = "disabled"; + return { result: config }; + }, + }, + "btc-rpc-proxy": { + async check(effects, configInput) { + effects.info("check btc-rpc-proxy"); + for (const checker of proxyChecks) { + const error = checker.currentError(configInput); + if (error) { + effects.error(`throwing error: ${error}`); + return { error }; + } + } + return { result: null }; + }, + async autoConfigure(effects, configInput) { + effects.info("autoconfigure btc-rpc-proxy"); + for (const checker of proxyChecks) { + const error = checker.currentError(configInput); + if (error) { + checker.fix(configInput); + } + } + return { result: configInput }; + }, + }, +}; \ No newline at end of file diff --git a/scripts/services/getConfig.ts b/scripts/services/getConfig.ts new file mode 100644 index 0000000..9239e5f --- /dev/null +++ b/scripts/services/getConfig.ts @@ -0,0 +1,113 @@ +import { ConfigRes, ExpectedExports, matches, YAML } from "../deps.ts"; + +const { any, string, dictionary } = matches; + +const matchConfig = dictionary([string, any]); + +export const getConfig: ExpectedExports.getConfig = async (effects) => { + const config = await effects + .readFile({ + path: "start9/config.yaml", + volumeId: "main", + }) + .then((x) => YAML.parse(x)) + .then((x) => matchConfig.unsafeCast(x)) + .catch((e) => { + effects.warn(`Got error ${e} while trying to read the config`); + return undefined; + }); + const spec: ConfigRes["spec"] = { + "tor-address": { + "name": "Tor Address", + "description": "The Tor address of the network interface", + "type": "pointer", + "subtype": "package", + "package-id": "mempool", + "target": "tor-address", + "interface": "main", + }, + "bitcoind": { + "type": "union", + "name": "Bitcoin Core", + "description": "The Bitcoin Core node to connect to:\n - internal: The Bitcoin Core or Proxy services installed to your Embassy\n", + "tag": { + "id": "type", + "name": "Type", + "variant-names": { + "internal": "Bitcoin Core", + "internal-proxy": "Bitcoin Proxy" + }, + "description": "The Bitcoin Core node to connect to:\n - internal: The Bitcoin Core and Proxy services installed to your Embassy\n" + }, + "default": "internal-proxy", + "variants": { + "internal": { + "user": { + "type": "pointer", + "name": "RPC Username", + "description": "The username for Bitcoin Core's RPC interface", + "subtype": "package", + "package-id": "bitcoind", + "target": "config", + "multi": false, + "selector": "$.rpc.username" + }, + "password": { + "type": "pointer", + "name": "RPC Password", + "description": "The password for Bitcoin Core's RPC interface", + "subtype": "package", + "package-id": "bitcoind", + "target": "config", + "multi": false, + "selector": "$.rpc.password" + } + }, + "internal-proxy": { + "user": { + "type": "pointer", + "name": "RPC Username", + "description": "The username for the RPC user allocated to electrs", + "subtype": "package", + "package-id": "btc-rpc-proxy", + "target": "config", + "multi": false, + "selector": "$.users[?(@.name == \"mempool\")].name" + }, + "password": { + "type": "pointer", + "name": "RPC Password", + "description": "The password for the RPC user allocated to electrs", + "subtype": "package", + "package-id": "btc-rpc-proxy", + "target": "config", + "multi": false, + "selector": "$.users[?(@.name == \"mempool\")].password" + }, + "txindex": { + "name": "Transaction Indexer", + "description": "The Transaction Indexer for Bitcoin Core", + "type": "pointer", + "subtype": "package", + "package-id": "bitcoind", + "target": "config", + "multi": false, + "selector": "$.txindex" + }, + } + } + }, + "enable-electrs": { + "name": "Enable Electrs Address Lookups", + "description": "Enables address lookups via an internal electrs instance", + "type": "boolean", + "default": true, + }, + }; + return { + result: { + config, + spec, + }, + }; +}; diff --git a/scripts/services/properties.ts b/scripts/services/properties.ts new file mode 100644 index 0000000..08f6943 --- /dev/null +++ b/scripts/services/properties.ts @@ -0,0 +1,36 @@ +import { Effects, ExpectedExports, YAML } from "../deps.ts"; + +export const properties: ExpectedExports.properties = async ( + effects: Effects, +) => { + try { + await effects.metadata({ + path: "start9/stats.yaml", + volumeId: "main", + }) + } catch { + return { + result: { + version: 2, + data: { + "Not Ready": { + type: "string", + value: "Could not find properties. The service might still be starting", + qr: false, + copyable: false, + masked: false, + description: "Fallback Message When Properties could not be found" + } + } + } + } + } + return { + result: YAML.parse( + await effects.readFile({ + path: "start9/stats.yaml", + volumeId: "main", + }), + ) as any, + }; +}; diff --git a/scripts/services/setConfig.ts b/scripts/services/setConfig.ts new file mode 100644 index 0000000..6ba2a2f --- /dev/null +++ b/scripts/services/setConfig.ts @@ -0,0 +1,36 @@ +import { + Config, + Effects, + ExpectedExports, + matches, + SetResult, + YAML, +} from "../deps.ts"; +const { number } = matches; + +export const setConfig: ExpectedExports.setConfig = async ( + effects: Effects, + newConfig: Config, +) => { + await effects.createDir({ + path: "start9", + volumeId: "main", + }); + await effects.writeFile({ + path: "start9/config.yaml", + toWrite: YAML.stringify(newConfig), + volumeId: "main", + }); + + const dependsOnElectrs: {[key: string]: string[]} = !!newConfig?.['enable-electrs'] ? {electrs: ['synced']} : {} + const dependsOnBitcoind: {[key: string]: string[]} = !!newConfig?.txindex ? {bitcoind: []} : {} + + const result: SetResult = { + signal: "SIGTERM", + "depends-on": { + ...dependsOnElectrs, + ...dependsOnBitcoind, + }, + }; + return { result }; +}; \ No newline at end of file