diff options
| author | Lilian Saget-Lethias <lilian.sagetlethias@gmail.com> | 2019-11-18 15:39:32 +0100 |
|---|---|---|
| committer | Ry Dahl <ry@tinyclouds.org> | 2019-11-18 09:39:32 -0500 |
| commit | 5671d38d8f0176c2828a242a79a856fcfae93c3e (patch) | |
| tree | 54e059f109baae9b3ff9161847149ecdac753e50 /std/encoding/yaml/type | |
| parent | a2f5bccad7f73607dc4ec20bdb60c6c4ac8dc9e6 (diff) | |
feat: Add std/encoding/yaml module (#3361)
Diffstat (limited to 'std/encoding/yaml/type')
| -rw-r--r-- | std/encoding/yaml/type/binary.ts | 139 | ||||
| -rw-r--r-- | std/encoding/yaml/type/bool.ts | 39 | ||||
| -rw-r--r-- | std/encoding/yaml/type/float.ts | 125 | ||||
| -rw-r--r-- | std/encoding/yaml/type/int.ts | 191 | ||||
| -rw-r--r-- | std/encoding/yaml/type/map.ts | 14 | ||||
| -rw-r--r-- | std/encoding/yaml/type/merge.ts | 15 | ||||
| -rw-r--r-- | std/encoding/yaml/type/mod.ts | 18 | ||||
| -rw-r--r-- | std/encoding/yaml/type/nil.ts | 45 | ||||
| -rw-r--r-- | std/encoding/yaml/type/omap.ts | 46 | ||||
| -rw-r--r-- | std/encoding/yaml/type/pairs.ts | 49 | ||||
| -rw-r--r-- | std/encoding/yaml/type/seq.ts | 14 | ||||
| -rw-r--r-- | std/encoding/yaml/type/set.ts | 31 | ||||
| -rw-r--r-- | std/encoding/yaml/type/str.ts | 12 | ||||
| -rw-r--r-- | std/encoding/yaml/type/timestamp.ts | 96 |
14 files changed, 834 insertions, 0 deletions
diff --git a/std/encoding/yaml/type/binary.ts b/std/encoding/yaml/type/binary.ts new file mode 100644 index 000000000..7c4fc1f06 --- /dev/null +++ b/std/encoding/yaml/type/binary.ts @@ -0,0 +1,139 @@ +// Ported from js-yaml v3.13.1: +// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license. +// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. + +import { Type } from "../type.ts"; +import { Any } from "../utils.ts"; + +const { Buffer } = Deno; + +// [ 64, 65, 66 ] -> [ padding, CR, LF ] +const BASE64_MAP = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r"; + +function resolveYamlBinary(data: Any): boolean { + if (data === null) return false; + + let code: number; + let bitlen = 0; + const max = data.length; + const map = BASE64_MAP; + + // Convert one by one. + for (let idx = 0; idx < max; idx++) { + code = map.indexOf(data.charAt(idx)); + + // Skip CR/LF + if (code > 64) continue; + + // Fail on illegal characters + if (code < 0) return false; + + bitlen += 6; + } + + // If there are any bits left, source was corrupted + return bitlen % 8 === 0; +} + +function constructYamlBinary(data: string): Deno.Buffer { + // remove CR/LF & padding to simplify scan + const input = data.replace(/[\r\n=]/g, ""); + const max = input.length; + const map = BASE64_MAP; + + // Collect by 6*4 bits (3 bytes) + + 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)); + } + + // Dump tail + + 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: Uint8Array): string { + const max = object.length; + const map = BASE64_MAP; + + // Convert every three bytes to 4 ASCII characters. + + 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]; + } + + // Dump tail + + 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: Any): obj is Deno.Buffer { + const buf = new Buffer(); + try { + if (0 > buf.readFromSync(obj as Deno.Buffer)) return true; + return false; + } catch { + return false; + } finally { + buf.reset(); + } +} + +export const binary = new Type("tag:yaml.org,2002:binary", { + construct: constructYamlBinary, + kind: "scalar", + predicate: isBinary, + represent: representYamlBinary, + resolve: resolveYamlBinary +}); diff --git a/std/encoding/yaml/type/bool.ts b/std/encoding/yaml/type/bool.ts new file mode 100644 index 000000000..28e9b2e9e --- /dev/null +++ b/std/encoding/yaml/type/bool.ts @@ -0,0 +1,39 @@ +// Ported from js-yaml v3.13.1: +// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da +// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license. +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. + +import { Type } from "../type.ts"; +import { isBoolean } from "../utils.ts"; + +function resolveYamlBoolean(data: string): boolean { + const max = data.length; + + return ( + (max === 4 && (data === "true" || data === "True" || data === "TRUE")) || + (max === 5 && (data === "false" || data === "False" || data === "FALSE")) + ); +} + +function constructYamlBoolean(data: string): boolean { + return data === "true" || data === "True" || data === "TRUE"; +} + +export const bool = new Type("tag:yaml.org,2002:bool", { + construct: constructYamlBoolean, + defaultStyle: "lowercase", + kind: "scalar", + predicate: isBoolean, + represent: { + lowercase(object: boolean): string { + return object ? "true" : "false"; + }, + uppercase(object: boolean): string { + return object ? "TRUE" : "FALSE"; + }, + camelcase(object: boolean): string { + return object ? "True" : "False"; + } + }, + resolve: resolveYamlBoolean +}); diff --git a/std/encoding/yaml/type/float.ts b/std/encoding/yaml/type/float.ts new file mode 100644 index 000000000..359a7cc37 --- /dev/null +++ b/std/encoding/yaml/type/float.ts @@ -0,0 +1,125 @@ +// Ported from js-yaml v3.13.1: +// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da +// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license. +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. + +import { StyleVariant, Type } from "../type.ts"; +import { isNegativeZero, Any } from "../utils.ts"; + +const YAML_FLOAT_PATTERN = new RegExp( + // 2.5e4, 2.5 and integers + "^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?" + + // .2e4, .2 + // special case, seems not from spec + "|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?" + + // 20:59 + "|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*" + + // .inf + "|[-+]?\\.(?:inf|Inf|INF)" + + // .nan + "|\\.(?:nan|NaN|NAN))$" +); + +function resolveYamlFloat(data: string): boolean { + if ( + !YAML_FLOAT_PATTERN.test(data) || + // Quick hack to not allow integers end with `_` + // Probably should update regexp & check speed + data[data.length - 1] === "_" + ) { + return false; + } + + return true; +} + +function constructYamlFloat(data: string): number { + let value = data.replace(/_/g, "").toLowerCase(); + const sign = value[0] === "-" ? -1 : 1; + const digits: number[] = []; + + 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): void => { + digits.unshift(parseFloat(v)); + }); + + let valueNb = 0.0; + let base = 1; + + digits.forEach((d): void => { + valueNb += d * base; + base *= 60; + }); + + return sign * valueNb; + } + return sign * parseFloat(value); +} + +const SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/; + +function representYamlFloat(object: Any, style?: StyleVariant): Any { + 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); + + // JS stringifier can build scientific format without dots: 5e-100, + // while YAML requres dot: 5.e-100. Fix it with simple hack + + return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace("e", ".e") : res; +} + +function isFloat(object: Any): boolean { + return ( + Object.prototype.toString.call(object) === "[object Number]" && + (object % 1 !== 0 || isNegativeZero(object)) + ); +} + +export const float = new Type("tag:yaml.org,2002:float", { + construct: constructYamlFloat, + defaultStyle: "lowercase", + kind: "scalar", + predicate: isFloat, + represent: representYamlFloat, + resolve: resolveYamlFloat +}); diff --git a/std/encoding/yaml/type/int.ts b/std/encoding/yaml/type/int.ts new file mode 100644 index 000000000..d2ffb1701 --- /dev/null +++ b/std/encoding/yaml/type/int.ts @@ -0,0 +1,191 @@ +// Ported from js-yaml v3.13.1: +// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da +// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license. +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. + +import { Type } from "../type.ts"; +import { isNegativeZero, Any } from "../utils.ts"; + +function isHexCode(c: number): boolean { + return ( + (0x30 /* 0 */ <= c && c <= 0x39) /* 9 */ || + (0x41 /* A */ <= c && c <= 0x46) /* F */ || + (0x61 /* a */ <= c && c <= 0x66) /* f */ + ); +} + +function isOctCode(c: number): boolean { + return 0x30 /* 0 */ <= c && c <= 0x37 /* 7 */; +} + +function isDecCode(c: number): boolean { + return 0x30 /* 0 */ <= c && c <= 0x39 /* 9 */; +} + +function resolveYamlInteger(data: string): boolean { + const max = data.length; + let index = 0; + let hasDigits = false; + + if (!max) return false; + + let ch = data[index]; + + // sign + if (ch === "-" || ch === "+") { + ch = data[++index]; + } + + if (ch === "0") { + // 0 + if (index + 1 === max) return true; + ch = data[++index]; + + // base 2, base 8, base 16 + + if (ch === "b") { + // base 2 + 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") { + // base 16 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === "_") continue; + if (!isHexCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && ch !== "_"; + } + + // base 8 + for (; index < max; index++) { + ch = data[index]; + if (ch === "_") continue; + if (!isOctCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && ch !== "_"; + } + + // base 10 (except 0) or base 60 + + // value should not start with `_`; + 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; + } + + // Should have digits and should not end with `_` + if (!hasDigits || ch === "_") return false; + + // if !base60 - done; + if (ch !== ":") return true; + + // base60 almost not used, no needs to optimize + return /^(:[0-5]?[0-9])+$/.test(data.slice(index)); +} + +function constructYamlInteger(data: string): number { + let value = data; + const digits: number[] = []; + + 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): void => { + digits.unshift(parseInt(v, 10)); + }); + + let valueInt = 0; + let base = 1; + + digits.forEach((d): void => { + valueInt += d * base; + base *= 60; + }); + + return sign * valueInt; + } + + return sign * parseInt(value, 10); +} + +function isInteger(object: Any): boolean { + return ( + Object.prototype.toString.call(object) === "[object Number]" && + object % 1 === 0 && + !isNegativeZero(object) + ); +} + +export const int = new Type("tag:yaml.org,2002:int", { + construct: constructYamlInteger, + defaultStyle: "decimal", + kind: "scalar", + predicate: isInteger, + represent: { + binary(obj: number): string { + return obj >= 0 + ? `0b${obj.toString(2)}` + : `-0b${obj.toString(2).slice(1)}`; + }, + octal(obj: number): string { + return obj >= 0 ? `0${obj.toString(8)}` : `-0${obj.toString(8).slice(1)}`; + }, + decimal(obj: number): string { + return obj.toString(10); + }, + hexadecimal(obj: number): string { + 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"] + } +}); diff --git a/std/encoding/yaml/type/map.ts b/std/encoding/yaml/type/map.ts new file mode 100644 index 000000000..6d273254d --- /dev/null +++ b/std/encoding/yaml/type/map.ts @@ -0,0 +1,14 @@ +// Ported from js-yaml v3.13.1: +// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da +// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license. +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. + +import { Type } from "../type.ts"; +import { Any } from "../utils.ts"; + +export const map = new Type("tag:yaml.org,2002:map", { + construct(data): Any { + return data !== null ? data : {}; + }, + kind: "mapping" +}); diff --git a/std/encoding/yaml/type/merge.ts b/std/encoding/yaml/type/merge.ts new file mode 100644 index 000000000..9389a0d20 --- /dev/null +++ b/std/encoding/yaml/type/merge.ts @@ -0,0 +1,15 @@ +// Ported from js-yaml v3.13.1: +// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da +// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license. +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. + +import { Type } from "../type.ts"; + +function resolveYamlMerge(data: string): boolean { + return data === "<<" || data === null; +} + +export const merge = new Type("tag:yaml.org,2002:merge", { + kind: "scalar", + resolve: resolveYamlMerge +}); diff --git a/std/encoding/yaml/type/mod.ts b/std/encoding/yaml/type/mod.ts new file mode 100644 index 000000000..1970753df --- /dev/null +++ b/std/encoding/yaml/type/mod.ts @@ -0,0 +1,18 @@ +// Ported from js-yaml v3.13.1: +// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da +// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license. +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. + +export { binary } from "./binary.ts"; +export { bool } from "./bool.ts"; +export { float } from "./float.ts"; +export { int } from "./int.ts"; +export { map } from "./map.ts"; +export { merge } from "./merge.ts"; +export { nil } from "./nil.ts"; +export { omap } from "./omap.ts"; +export { pairs } from "./pairs.ts"; +export { seq } from "./seq.ts"; +export { set } from "./set.ts"; +export { str } from "./str.ts"; +export { timestamp } from "./timestamp.ts"; diff --git a/std/encoding/yaml/type/nil.ts b/std/encoding/yaml/type/nil.ts new file mode 100644 index 000000000..c7e87f96d --- /dev/null +++ b/std/encoding/yaml/type/nil.ts @@ -0,0 +1,45 @@ +// Ported from js-yaml v3.13.1: +// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da +// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license. +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. + +import { Type } from "../type.ts"; + +function resolveYamlNull(data: string): boolean { + const max = data.length; + + return ( + (max === 1 && data === "~") || + (max === 4 && (data === "null" || data === "Null" || data === "NULL")) + ); +} + +function constructYamlNull(): null { + return null; +} + +function isNull(object: unknown): object is null { + return object === null; +} + +export const nil = new Type("tag:yaml.org,2002:null", { + construct: constructYamlNull, + defaultStyle: "lowercase", + kind: "scalar", + predicate: isNull, + represent: { + canonical(): string { + return "~"; + }, + lowercase(): string { + return "null"; + }, + uppercase(): string { + return "NULL"; + }, + camelcase(): string { + return "Null"; + } + }, + resolve: resolveYamlNull +}); diff --git a/std/encoding/yaml/type/omap.ts b/std/encoding/yaml/type/omap.ts new file mode 100644 index 000000000..1b7a79a50 --- /dev/null +++ b/std/encoding/yaml/type/omap.ts @@ -0,0 +1,46 @@ +// Ported from js-yaml v3.13.1: +// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da +// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license. +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. + +import { Type } from "../type.ts"; +import { Any } from "../utils.ts"; + +const _hasOwnProperty = Object.prototype.hasOwnProperty; +const _toString = Object.prototype.toString; + +function resolveYamlOmap(data: Any): boolean { + const objectKeys: string[] = []; + 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 (_hasOwnProperty.call(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: Any): Any { + return data !== null ? data : []; +} + +export const omap = new Type("tag:yaml.org,2002:omap", { + construct: constructYamlOmap, + kind: "sequence", + resolve: resolveYamlOmap +}); diff --git a/std/encoding/yaml/type/pairs.ts b/std/encoding/yaml/type/pairs.ts new file mode 100644 index 000000000..37f8eb630 --- /dev/null +++ b/std/encoding/yaml/type/pairs.ts @@ -0,0 +1,49 @@ +// Ported from js-yaml v3.13.1: +// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da +// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license. +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. + +import { Type } from "../type.ts"; +import { Any } from "../utils.ts"; + +const _toString = Object.prototype.toString; + +function resolveYamlPairs(data: Any[][]): boolean { + const result = new Array(data.length); + + for (let index = 0; index < data.length; index++) { + const pair = data[index]; + + if (_toString.call(pair) !== "[object Object]") return false; + + const keys = Object.keys(pair); + + if (keys.length !== 1) return false; + + result[index] = [keys[0], pair[keys[0] as Any]]; + } + + return true; +} + +function constructYamlPairs(data: string): Any[] { + if (data === null) return []; + + const result = new Array(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] as Any]]; + } + + return result; +} + +export const pairs = new Type("tag:yaml.org,2002:pairs", { + construct: constructYamlPairs, + kind: "sequence", + resolve: resolveYamlPairs +}); diff --git a/std/encoding/yaml/type/seq.ts b/std/encoding/yaml/type/seq.ts new file mode 100644 index 000000000..32c700b6e --- /dev/null +++ b/std/encoding/yaml/type/seq.ts @@ -0,0 +1,14 @@ +// Ported from js-yaml v3.13.1: +// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da +// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license. +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. + +import { Type } from "../type.ts"; +import { Any } from "../utils.ts"; + +export const seq = new Type("tag:yaml.org,2002:seq", { + construct(data): Any { + return data !== null ? data : []; + }, + kind: "sequence" +}); diff --git a/std/encoding/yaml/type/set.ts b/std/encoding/yaml/type/set.ts new file mode 100644 index 000000000..3273223f7 --- /dev/null +++ b/std/encoding/yaml/type/set.ts @@ -0,0 +1,31 @@ +// Ported from js-yaml v3.13.1: +// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da +// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license. +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. + +import { Type } from "../type.ts"; +import { Any } from "../utils.ts"; + +const _hasOwnProperty = Object.prototype.hasOwnProperty; + +function resolveYamlSet(data: Any): boolean { + if (data === null) return true; + + for (const key in data) { + if (_hasOwnProperty.call(data, key)) { + if (data[key] !== null) return false; + } + } + + return true; +} + +function constructYamlSet(data: string): Any { + return data !== null ? data : {}; +} + +export const set = new Type("tag:yaml.org,2002:set", { + construct: constructYamlSet, + kind: "mapping", + resolve: resolveYamlSet +}); diff --git a/std/encoding/yaml/type/str.ts b/std/encoding/yaml/type/str.ts new file mode 100644 index 000000000..8c24e9398 --- /dev/null +++ b/std/encoding/yaml/type/str.ts @@ -0,0 +1,12 @@ +// Ported from js-yaml v3.13.1: +// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. + +import { Type } from "../type.ts"; + +export const str = new Type("tag:yaml.org,2002:str", { + construct(data): string { + return data !== null ? data : ""; + }, + kind: "scalar" +}); diff --git a/std/encoding/yaml/type/timestamp.ts b/std/encoding/yaml/type/timestamp.ts new file mode 100644 index 000000000..38cc9d940 --- /dev/null +++ b/std/encoding/yaml/type/timestamp.ts @@ -0,0 +1,96 @@ +// Ported from js-yaml v3.13.1: +// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da +// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license. +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. + +import { Type } from "../type.ts"; + +const YAML_DATE_REGEXP = new RegExp( + "^([0-9][0-9][0-9][0-9])" + // [1] year + "-([0-9][0-9])" + // [2] month + "-([0-9][0-9])$" // [3] day +); + +const YAML_TIMESTAMP_REGEXP = new RegExp( + "^([0-9][0-9][0-9][0-9])" + // [1] year + "-([0-9][0-9]?)" + // [2] month + "-([0-9][0-9]?)" + // [3] day + "(?:[Tt]|[ \\t]+)" + // ... + "([0-9][0-9]?)" + // [4] hour + ":([0-9][0-9])" + // [5] minute + ":([0-9][0-9])" + // [6] second + "(?:\\.([0-9]*))?" + // [7] fraction + "(?:[ \\t]*(Z|([-+])([0-9][0-9]?)" + // [8] tz [9] tz_sign [10] tz_hour + "(?::([0-9][0-9]))?))?$" // [11] tz_minute +); + +function resolveYamlTimestamp(data: string): boolean { + 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: string): Date { + 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"); + + // match: [1] year [2] month [3] day + + const year = +match[1]; + const month = +match[2] - 1; // JS month starts with 0 + const day = +match[3]; + + if (!match[4]) { + // no hour + return new Date(Date.UTC(year, month, day)); + } + + // match: [4] hour [5] minute [6] second [7] fraction + + 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) { + // milli-seconds + partFraction += "0"; + } + fraction = +partFraction; + } + + // match: [8] tz [9] tz_sign [10] tz_hour [11] tz_minute + + let delta = null; + if (match[9]) { + const tzHour = +match[10]; + const tzMinute = +(match[11] || 0); + delta = (tzHour * 60 + tzMinute) * 60000; // delta in mili-seconds + 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: Date): string { + return date.toISOString(); +} + +export const timestamp = new Type("tag:yaml.org,2002:timestamp", { + construct: constructYamlTimestamp, + instanceOf: Date, + kind: "scalar", + represent: representYamlTimestamp, + resolve: resolveYamlTimestamp +}); |
