diff options
Diffstat (limited to 'std/encoding')
75 files changed, 0 insertions, 10003 deletions
diff --git a/std/encoding/README.md b/std/encoding/README.md deleted file mode 100644 index 3c60c6fcd..000000000 --- a/std/encoding/README.md +++ /dev/null @@ -1,575 +0,0 @@ -# encoding - -Helper module for dealing with external data structures. - -- [`ascii85`](#ascii85) -- [`base32`](#base32) -- [`binary`](#binary) -- [`csv`](#csv) -- [`toml`](#toml) -- [`yaml`](#yaml) - -## Binary - -Implements equivalent methods to Go's `encoding/binary` package. - -Available Functions: - -```typescript -sizeof(dataType: RawTypes): number -getNBytes(r: Deno.Reader, n: number): Promise<Uint8Array> -varnum(b: Uint8Array, o: VarnumOptions = {}): number | null -varbig(b: Uint8Array, o: VarbigOptions = {}): bigint | null -putVarnum(b: Uint8Array, x: number, o: VarnumOptions = {}): number -putVarbig(b: Uint8Array, x: bigint, o: VarbigOptions = {}): number -readVarnum(r: Deno.Reader, o: VarnumOptions = {}): Promise<number> -readVarbig(r: Deno.Reader, o: VarbigOptions = {}): Promise<bigint> -writeVarnum(w: Deno.Writer, x: number, o: VarnumOptions = {}): Promise<number> -writeVarbig(w: Deno.Writer, x: bigint, o: VarbigOptions = {}): Promise<number> -``` - -## CSV - -### API - -#### `readMatrix` - -```ts -(reader: BufReader, opt: ReadOptions = { - comma: ",", - trimLeadingSpace: false, - lazyQuotes: false, -}): Promise<string[][]> -``` - -Parse the CSV from the `reader` with the options provided and return -`string[][]`. - -#### `parse` - -```ts -(input: string | BufReader, opt: ParseOptions = { skipFirstRow: false }): Promise<unknown[]> -``` - -Parse the CSV string/buffer with the options provided. The result of this -function is as follows: - -- If you don't provide `opt.skipFirstRow`, `opt.parse`, and `opt.columns`, it - returns `string[][]`. -- If you provide `opt.skipFirstRow` or `opt.columns` but not `opt.parse`, it - returns `object[]`. -- If you provide `opt.parse`, it returns an array where each element is the - value returned from `opt.parse`. - -##### `ParseOptions` - -- **`skipFirstRow: boolean;`**: If you provide `skipFirstRow: true` and - `columns`, the first line will be skipped. If you provide `skipFirstRow: true` - but not `columns`, the first line will be skipped and used as header - definitions. -- **`columns: string[] | HeaderOptions[];`**: If you provide `string[]` or - `ColumnOptions[]`, those names will be used for header definition. -- **`parse?: (input: unknown) => unknown;`**: Parse function for the row, which - will be executed after parsing of all columns. Therefore if you don't provide - `skipFirstRow`, `columns`, and `parse` function, input will be `string[]`. - -##### `HeaderOptions` - -- **`name: string;`**: Name of the header to be used as property. -- **`parse?: (input: string) => unknown;`**: Parse function for the column. This - is executed on each entry of the header. This can be combined with the Parse - function of the rows. - -##### `ReadOptions` - -- **`comma?: string;`**: Character which separates values. Default: `","`. -- **`comment?: string;`**: Character to start a comment. Default: `"#"`. -- **`trimLeadingSpace?: boolean;`**: Flag to trim the leading space of the - value. Default: `false`. -- **`lazyQuotes?: boolean;`**: Allow unquoted quote in a quoted field or non - double quoted quotes in quoted field. Default: `false`. -- **`fieldsPerRecord?`**: Enabling the check of fields for each row. If == 0, - first row is used as referral for the number of fields. - -#### `stringify` - -```ts -(data: DataItem[], columns: Column[], options?: StringifyOptions): Promise<string> -``` - -- **`data`** is the source data to stringify. It's an array of items which are - plain objects or arrays. - - `DataItem: Record<string, unknown> | unknown[]` - - ```ts - const data = [ - { - name: "Deno", - repo: { org: "denoland", name: "deno" }, - runsOn: ["Rust", "TypeScript"], - }, - ]; - ``` - -- **`columns`** is a list of instructions for how to target and transform the - data for each column of output. This is also where you can provide an explicit - header name for the column. - - `Column`: - - - The most essential aspect of a column is accessing the property holding the - data for that column on each object in the data array. If that member is at - the top level, `Column` can simply be a property accessor, which is either a - `string` (if it's a plain object) or a `number` (if it's an array). - - ```ts - const columns = [ - "name", - ]; - ``` - - Each property accessor will be used as the header for the column: - - | name | - | :--: | - | Deno | - - - If the required data is not at the top level (it's nested in other - objects/arrays), then a simple property accessor won't work, so an array of - them will be required. - - ```ts - const columns = [ - ["repo", "name"], - ["repo", "org"], - ]; - ``` - - When using arrays of property accessors, the header names inherit the value - of the last accessor in each array: - - | name | org | - | :--: | :------: | - | deno | denoland | - - - If the data is not already in the required output format, or a different - column header is desired, then a `ColumnDetails` object type can be used for - each column: - - - **`fn?: (value: any) => string | Promise<string>`** is an optional - function to transform the targeted data into the desired format - - - **`header?: string`** is the optional value to use for the column header - name - - - **`prop: PropertyAccessor | PropertyAccessor[]`** is the property accessor - (`string` or `number`) or array of property accessors used to access the - data on each object - - ```ts - const columns = [ - "name", - { - prop: ["runsOn", 0], - header: "language 1", - fn: (str: string) => str.toLowerCase(), - }, - { - prop: ["runsOn", 1], - header: "language 2", - fn: (str: string) => str.toLowerCase(), - }, - ]; - ``` - - | name | language 1 | language 2 | - | :--: | :--------: | :--------: | - | Deno | rust | typescript | - -- **`options`** are options for the delimiter-separated output. - - - **`headers?: boolean`**: Whether or not to include the row of headers. - Default: `true` - - - **`separator?: string`**: Delimiter used to separate values. Examples: - - `","` _comma_ (Default) - - `"\t"` _tab_ - - `"|"` _pipe_ - - etc. - -### Basic Usage - -```ts -import { parse } from "https://deno.land/std@$STD_VERSION/encoding/csv.ts"; -const string = "a,b,c\nd,e,f"; - -console.log( - await parse(string, { - skipFirstRow: false, - }), -); -// output: -// [["a", "b", "c"], ["d", "e", "f"]] -``` - -```ts -import { - Column, - stringify, -} from "https://deno.land/std@$STD_VERSION/encoding/csv.ts"; - -type Character = { - age: number; - name: { - first: string; - last: string; - }; -}; - -const data: Character[] = [ - { - age: 70, - name: { - first: "Rick", - last: "Sanchez", - }, - }, - { - age: 14, - name: { - first: "Morty", - last: "Smith", - }, - }, -]; - -let columns: Column[] = [ - ["name", "first"], - "age", -]; - -console.log(await stringify(data, columns)); -// first,age -// Rick,70 -// Morty,14 -// - -columns = [ - { - prop: "name", - fn: (name: Character["name"]) => `${name.first} ${name.last}`, - }, - { - prop: "age", - header: "is_adult", - fn: (age: Character["age"]) => String(age >= 18), - }, -]; - -console.log(await stringify(data, columns, { separator: "\t" })); -// name is_adult -// Rick Sanchez true -// Morty Smith false -// -``` - -## TOML - -This module parse TOML files. It follows as much as possible the -[TOML specs](https://toml.io/en/latest). Be sure to read the supported types as -not every specs is supported at the moment and the handling in TypeScript side -is a bit different. - -### Supported types and handling - -- :heavy_check_mark: [Keys](https://toml.io/en/latest#keys) -- :exclamation: [String](https://toml.io/en/latest#string) -- :heavy_check_mark: [Multiline String](https://toml.io/en/latest#string) -- :heavy_check_mark: [Literal String](https://toml.io/en/latest#string) -- :exclamation: [Integer](https://toml.io/en/latest#integer) -- :heavy_check_mark: [Float](https://toml.io/en/latest#float) -- :heavy_check_mark: [Boolean](https://toml.io/en/latest#boolean) -- :heavy_check_mark: - [Offset Date-time](https://toml.io/en/latest#offset-date-time) -- :heavy_check_mark: - [Local Date-time](https://toml.io/en/latest#local-date-time) -- :heavy_check_mark: [Local Date](https://toml.io/en/latest#local-date) -- :exclamation: [Local Time](https://toml.io/en/latest#local-time) -- :heavy_check_mark: [Table](https://toml.io/en/latest#table) -- :heavy_check_mark: [Inline Table](https://toml.io/en/latest#inline-table) -- :exclamation: [Array of Tables](https://toml.io/en/latest#array-of-tables) - -:exclamation: _Supported with warnings see [Warning](#Warning)._ - -#### :warning: Warning - -##### String - -- Regex : Due to the spec, there is no flag to detect regex properly in a TOML - declaration. So the regex is stored as string. - -##### Integer - -For **Binary** / **Octal** / **Hexadecimal** numbers, they are stored as string -to be not interpreted as Decimal. - -##### Local Time - -Because local time does not exist in JavaScript, the local time is stored as a -string. - -##### Inline Table - -Inline tables are supported. See below: - -```toml -animal = { type = { name = "pug" } } -## Output { animal: { type: { name: "pug" } } } -animal = { type.name = "pug" } -## Output { animal: { type : { name : "pug" } } -animal.as.leaders = "tosin" -## Output { animal: { as: { leaders: "tosin" } } } -"tosin.abasi" = "guitarist" -## Output { tosin.abasi: "guitarist" } -``` - -##### Array of Tables - -At the moment only simple declarations like below are supported: - -```toml -[[bin]] -name = "deno" -path = "cli/main.rs" - -[[bin]] -name = "deno_core" -path = "src/foo.rs" - -[[nib]] -name = "node" -path = "not_found" -``` - -will output: - -```json -{ - "bin": [ - { "name": "deno", "path": "cli/main.rs" }, - { "name": "deno_core", "path": "src/foo.rs" } - ], - "nib": [{ "name": "node", "path": "not_found" }] -} -``` - -### Basic usage - -```ts -import { - parse, - stringify, -} from "https://deno.land/std@$STD_VERSION/encoding/toml.ts"; -const obj = { - bin: [ - { name: "deno", path: "cli/main.rs" }, - { name: "deno_core", path: "src/foo.rs" }, - ], - nib: [{ name: "node", path: "not_found" }], -}; -const tomlString = stringify(obj); -console.log(tomlString); - -// => -// [[bin]] -// name = "deno" -// path = "cli/main.rs" - -// [[bin]] -// name = "deno_core" -// path = "src/foo.rs" - -// [[nib]] -// name = "node" -// path = "not_found" - -const tomlObject = parse(tomlString); -console.log(tomlObject); - -// => -// { -// bin: [ -// { name: "deno", path: "cli/main.rs" }, -// { name: "deno_core", path: "src/foo.rs" } -// ], -// nib: [ { name: "node", path: "not_found" } ] -// } -``` - -## YAML - -YAML parser / dumper for Deno. - -Heavily inspired from [`js-yaml`](https://github.com/nodeca/js-yaml). - -### Basic usage - -`parse` parses the yaml string, and `stringify` dumps the given object to YAML -string. - -```ts -import { - parse, - stringify, -} from "https://deno.land/std@$STD_VERSION/encoding/yaml.ts"; - -const data = parse(` -foo: bar -baz: - - qux - - quux -`); -console.log(data); -// => { foo: "bar", baz: [ "qux", "quux" ] } - -const yaml = stringify({ foo: "bar", baz: ["qux", "quux"] }); -console.log(yaml); -// => -// foo: bar -// baz: -// - qux -// - quux -``` - -If your YAML contains multiple documents in it, you can use `parseAll` for -handling it. - -```ts -import { parseAll } from "https://deno.land/std@$STD_VERSION/encoding/yaml.ts"; - -const data = parseAll(` ---- -id: 1 -name: Alice ---- -id: 2 -name: Bob ---- -id: 3 -name: Eve -`); -console.log(data); -// => [ { id: 1, name: "Alice" }, { id: 2, name: "Bob" }, { id: 3, name: "Eve" } ] -``` - -### API - -#### `parse(str: string, opts?: ParserOption): unknown` - -Parses the YAML string with a single document. - -#### `parseAll(str: string, iterator?: Function, opts?: ParserOption): unknown` - -Parses the YAML string with multiple documents. If the iterator is given, it's -applied to every document instead of returning the array of parsed objects. - -#### `stringify(obj: object, opts?: DumpOption): string` - -Serializes `object` as a YAML document. - -### :warning: Limitations - -- `binary` type is currently not stable. -- `function`, `regexp`, and `undefined` type are currently not supported. - -### More example - -See: https://github.com/nodeca/js-yaml - -## base32 - -[RFC4648 base32](https://tools.ietf.org/html/rfc4648#section-6) encoder/decoder -for Deno. - -### Basic usage - -`encode` encodes a `Uint8Array` to RFC4648 base32 representation, and `decode` -decodes the given RFC4648 base32 representation to a `Uint8Array`. - -```ts -import { - decode, - encode, -} from "https://deno.land/std@$STD_VERSION/encoding/base32.ts"; - -const b32Repr = "RC2E6GA="; - -const binaryData = decode(b32Repr); -console.log(binaryData); -// => Uint8Array [ 136, 180, 79, 24 ] - -console.log(encode(binaryData)); -// => RC2E6GA= -``` - -## ascii85 - -Ascii85/base85 encoder and decoder with support for multiple standards. - -### Basic usage - -`encode` encodes a `Uint8Array` to a ascii85 representation, and `decode` -decodes the given ascii85 representation to a `Uint8Array`. - -```ts -import { - decode, - encode, -} from "https://deno.land/std@$STD_VERSION/encoding/ascii85.ts"; - -const a85Repr = "LpTqp"; - -const binaryData = decode(a85Repr); -console.log(binaryData); -// => Uint8Array [ 136, 180, 79, 24 ] - -console.log(encode(binaryData)); -// => LpTqp -``` - -### Specifying a standard and delimiter - -By default all functions are using the most popular Adobe version of ascii85 and -not adding any delimiter. However, there are three more standards supported - -btoa (different delimiter and additional compression of 4 bytes equal to 32), -[Z85](https://rfc.zeromq.org/spec/32/) and -[RFC 1924](https://tools.ietf.org/html/rfc1924). It's possible to use a -different encoding by specifying it in `options` object as a second parameter. - -Similarly, it's possible to make `encode` add a delimiter (`<~` and `~>` for -Adobe, `xbtoa Begin` and `xbtoa End` with newlines between the delimiters and -encoded data for btoa. Checksums for btoa are not supported. Delimiters are not -supported by other encodings.) - -encoding examples: - -```ts -import { - decode, - encode, -} from "https://deno.land/std@$STD_VERSION/encoding/ascii85.ts"; -const binaryData = new Uint8Array([136, 180, 79, 24]); -console.log(encode(binaryData)); -// => LpTqp -console.log(encode(binaryData, { standard: "Adobe", delimiter: true })); -// => <~LpTqp~> -console.log(encode(binaryData, { standard: "btoa", delimiter: true })); -/* => xbtoa Begin -LpTqp -xbtoa End */ -console.log(encode(binaryData, { standard: "RFC 1924" })); -// => h_p`_ -console.log(encode(binaryData, { standard: "Z85" })); -// => H{P}{ -``` diff --git a/std/encoding/_yaml/dumper/dumper.ts b/std/encoding/_yaml/dumper/dumper.ts deleted file mode 100644 index 05dc56262..000000000 --- a/std/encoding/_yaml/dumper/dumper.ts +++ /dev/null @@ -1,896 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { YAMLError } from "../error.ts"; -import type { RepresentFn, StyleVariant, Type } from "../type.ts"; -import * as common from "../utils.ts"; -import { DumperState, DumperStateOptions } from "./dumper_state.ts"; - -type Any = common.Any; -type ArrayObject<T = Any> = common.ArrayObject<T>; - -const _toString = Object.prototype.toString; -const _hasOwnProperty = Object.prototype.hasOwnProperty; - -const CHAR_TAB = 0x09; /* Tab */ -const CHAR_LINE_FEED = 0x0a; /* LF */ -const CHAR_SPACE = 0x20; /* Space */ -const CHAR_EXCLAMATION = 0x21; /* ! */ -const CHAR_DOUBLE_QUOTE = 0x22; /* " */ -const CHAR_SHARP = 0x23; /* # */ -const CHAR_PERCENT = 0x25; /* % */ -const CHAR_AMPERSAND = 0x26; /* & */ -const CHAR_SINGLE_QUOTE = 0x27; /* ' */ -const CHAR_ASTERISK = 0x2a; /* * */ -const CHAR_COMMA = 0x2c; /* , */ -const CHAR_MINUS = 0x2d; /* - */ -const CHAR_COLON = 0x3a; /* : */ -const CHAR_GREATER_THAN = 0x3e; /* > */ -const CHAR_QUESTION = 0x3f; /* ? */ -const CHAR_COMMERCIAL_AT = 0x40; /* @ */ -const CHAR_LEFT_SQUARE_BRACKET = 0x5b; /* [ */ -const CHAR_RIGHT_SQUARE_BRACKET = 0x5d; /* ] */ -const CHAR_GRAVE_ACCENT = 0x60; /* ` */ -const CHAR_LEFT_CURLY_BRACKET = 0x7b; /* { */ -const CHAR_VERTICAL_LINE = 0x7c; /* | */ -const CHAR_RIGHT_CURLY_BRACKET = 0x7d; /* } */ - -const ESCAPE_SEQUENCES: { [char: number]: string } = {}; - -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: number): string { - const string = character.toString(16).toUpperCase(); - - let handle: string; - let length: number; - 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}${common.repeat("0", length - string.length)}${string}`; -} - -// Indents every line in a string. Empty lines (\n only) are not indented. -function indentString(string: string, spaces: number): string { - const ind = common.repeat(" ", spaces), - length = string.length; - let position = 0, - next = -1, - result = "", - line: string; - - 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: DumperState, level: number): string { - return `\n${common.repeat(" ", state.indent * level)}`; -} - -function testImplicitResolving(state: DumperState, str: string): boolean { - let type: 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; -} - -// [33] s-white ::= s-space | s-tab -function isWhitespace(c: number): boolean { - return c === CHAR_SPACE || c === CHAR_TAB; -} - -// Returns true if the character can be printed without escaping. -// From YAML 1.2: "any allowed characters known to be non-printable -// should also be escaped. [However,] This isn’t mandatory" -// Derived from nb-char - \t - #x85 - #xA0 - #x2028 - #x2029. -function isPrintable(c: number): boolean { - return ( - (0x00020 <= c && c <= 0x00007e) || - (0x000a1 <= c && c <= 0x00d7ff && c !== 0x2028 && c !== 0x2029) || - (0x0e000 <= c && c <= 0x00fffd && c !== 0xfeff) /* BOM */ || - (0x10000 <= c && c <= 0x10ffff) - ); -} - -// Simplified test for values allowed after the first character in plain style. -function isPlainSafe(c: number): boolean { - // Uses a subset of nb-char - c-flow-indicator - ":" - "#" - // where nb-char ::= c-printable - b-char - c-byte-order-mark. - return ( - isPrintable(c) && - c !== 0xfeff && - // - c-flow-indicator - c !== CHAR_COMMA && - c !== CHAR_LEFT_SQUARE_BRACKET && - c !== CHAR_RIGHT_SQUARE_BRACKET && - c !== CHAR_LEFT_CURLY_BRACKET && - c !== CHAR_RIGHT_CURLY_BRACKET && - // - ":" - "#" - c !== CHAR_COLON && - c !== CHAR_SHARP - ); -} - -// Simplified test for values allowed as the first character in plain style. -function isPlainSafeFirst(c: number): boolean { - // Uses a subset of ns-char - c-indicator - // where ns-char = nb-char - s-white. - return ( - isPrintable(c) && - c !== 0xfeff && - !isWhitespace(c) && // - s-white - // - (c-indicator ::= - // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}” - c !== CHAR_MINUS && - c !== CHAR_QUESTION && - c !== CHAR_COLON && - c !== CHAR_COMMA && - c !== CHAR_LEFT_SQUARE_BRACKET && - c !== CHAR_RIGHT_SQUARE_BRACKET && - c !== CHAR_LEFT_CURLY_BRACKET && - c !== CHAR_RIGHT_CURLY_BRACKET && - // | “#” | “&” | “*” | “!” | “|” | “>” | “'” | “"” - c !== CHAR_SHARP && - c !== CHAR_AMPERSAND && - c !== CHAR_ASTERISK && - c !== CHAR_EXCLAMATION && - c !== CHAR_VERTICAL_LINE && - c !== CHAR_GREATER_THAN && - c !== CHAR_SINGLE_QUOTE && - c !== CHAR_DOUBLE_QUOTE && - // | “%” | “@” | “`”) - c !== CHAR_PERCENT && - c !== CHAR_COMMERCIAL_AT && - c !== CHAR_GRAVE_ACCENT - ); -} - -// Determines whether block indentation indicator is required. -function needIndentIndicator(string: string): boolean { - const leadingSpaceRe = /^\n* /; - return leadingSpaceRe.test(string); -} - -const STYLE_PLAIN = 1, - STYLE_SINGLE = 2, - STYLE_LITERAL = 3, - STYLE_FOLDED = 4, - STYLE_DOUBLE = 5; - -// Determines which scalar styles are possible and returns the preferred style. -// lineWidth = -1 => no limit. -// Pre-conditions: str.length > 0. -// Post-conditions: -// STYLE_PLAIN or STYLE_SINGLE => no \n are in the string. -// STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1). -// STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1). -function chooseScalarStyle( - string: string, - singleLineOnly: boolean, - indentPerLevel: number, - lineWidth: number, - testAmbiguousType: (...args: Any[]) => Any, -): number { - const shouldTrackWidth = lineWidth !== -1; - let hasLineBreak = false, - hasFoldableLine = false, // only checked if shouldTrackWidth - previousLineBreak = -1, // count the first line correctly - plain = isPlainSafeFirst(string.charCodeAt(0)) && - !isWhitespace(string.charCodeAt(string.length - 1)); - - let char: number, i: number; - if (singleLineOnly) { - // Case: no block styles. - // Check for disallowed characters to rule out plain and single. - for (i = 0; i < string.length; i++) { - char = string.charCodeAt(i); - if (!isPrintable(char)) { - return STYLE_DOUBLE; - } - plain = plain && isPlainSafe(char); - } - } else { - // Case: block styles permitted. - for (i = 0; i < string.length; i++) { - char = string.charCodeAt(i); - if (char === CHAR_LINE_FEED) { - hasLineBreak = true; - // Check if any line can be folded. - if (shouldTrackWidth) { - hasFoldableLine = hasFoldableLine || - // Foldable line = too long, and not more-indented. - (i - previousLineBreak - 1 > lineWidth && - string[previousLineBreak + 1] !== " "); - previousLineBreak = i; - } - } else if (!isPrintable(char)) { - return STYLE_DOUBLE; - } - plain = plain && isPlainSafe(char); - } - // in case the end is missing a \n - hasFoldableLine = hasFoldableLine || - (shouldTrackWidth && - i - previousLineBreak - 1 > lineWidth && - string[previousLineBreak + 1] !== " "); - } - // Although every style can represent \n without escaping, prefer block styles - // for multiline, since they're more readable and they don't add empty lines. - // Also prefer folding a super-long line. - if (!hasLineBreak && !hasFoldableLine) { - // Strings interpretable as another type have to be quoted; - // e.g. the string 'true' vs. the boolean true. - return plain && !testAmbiguousType(string) ? STYLE_PLAIN : STYLE_SINGLE; - } - // Edge case: block indentation indicator can only have one digit. - if (indentPerLevel > 9 && needIndentIndicator(string)) { - return STYLE_DOUBLE; - } - // At this point we know block styles are valid. - // Prefer literal style unless we want to fold. - return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL; -} - -// Greedy line breaking. -// Picks the longest line under the limit each time, -// otherwise settles for the shortest line over the limit. -// NB. More-indented lines *cannot* be folded, as that would add an extra \n. -function foldLine(line: string, width: number): string { - if (line === "" || line[0] === " ") return line; - - // Since a more-indented line adds a \n, breaks can't be followed by a space. - const breakRe = / [^ ]/g; // note: the match index will always be <= length-2. - let match; - // start is an inclusive index. end, curr, and next are exclusive. - let start = 0, - end, - curr = 0, - next = 0; - let result = ""; - - // Invariants: 0 <= start <= length-1. - // 0 <= curr <= next <= max(0, length-2). curr - start <= width. - // Inside the loop: - // A match implies length >= 2, so curr and next are <= length-2. - // tslint:disable-next-line:no-conditional-assignment - while ((match = breakRe.exec(line))) { - next = match.index; - // maintain invariant: curr - start <= width - if (next - start > width) { - end = curr > start ? curr : next; // derive end <= length-2 - result += `\n${line.slice(start, end)}`; - // skip the space that was output as \n - start = end + 1; // derive start <= length-1 - } - curr = next; - } - - // By the invariants, start <= length-1, so there is something left over. - // It is either the whole string or a part starting from non-whitespace. - result += "\n"; - // Insert a break if the remainder is too long and there is a break available. - 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); // drop extra \n joiner -} - -// (See the note for writeScalar.) -function dropEndingNewline(string: string): string { - return string[string.length - 1] === "\n" ? string.slice(0, -1) : string; -} - -// Note: a long line without a suitable break point will exceed the width limit. -// Pre-conditions: every char in str isPrintable, str.length > 0, width > 0. -function foldString(string: string, width: number): string { - // In folded style, $k$ consecutive newlines output as $k+1$ newlines— - // unless they're before or after a more-indented line, or at the very - // beginning or end, in which case $k$ maps to $k$. - // Therefore, parse each chunk as newline(s) followed by a content line. - const lineRe = /(\n+)([^\n]*)/g; - - // first line (possibly an empty line) - let result = ((): string => { - let nextLF = string.indexOf("\n"); - nextLF = nextLF !== -1 ? nextLF : string.length; - lineRe.lastIndex = nextLF; - // eslint-disable-next-line @typescript-eslint/no-use-before-define - return foldLine(string.slice(0, nextLF), width); - })(); - // If we haven't reached the first content line yet, don't add an extra \n. - let prevMoreIndented = string[0] === "\n" || string[0] === " "; - let moreIndented; - - // rest of the lines - let match; - // tslint:disable-next-line:no-conditional-assignment - while ((match = lineRe.exec(string))) { - const prefix = match[1], - line = match[2]; - moreIndented = line[0] === " "; - result += prefix + - (!prevMoreIndented && !moreIndented && line !== "" ? "\n" : "") + - // eslint-disable-next-line @typescript-eslint/no-use-before-define - foldLine(line, width); - prevMoreIndented = moreIndented; - } - - return result; -} - -// Escapes a double-quoted string. -function escapeString(string: string): string { - let result = ""; - let char, nextChar; - let escapeSeq; - - for (let i = 0; i < string.length; i++) { - char = string.charCodeAt(i); - // Check for surrogate pairs (reference Unicode 3.0 section "3.7 Surrogates"). - if (char >= 0xd800 && char <= 0xdbff /* high surrogate */) { - nextChar = string.charCodeAt(i + 1); - if (nextChar >= 0xdc00 && nextChar <= 0xdfff /* low surrogate */) { - // Combine the surrogate pair and store it escaped. - result += encodeHex( - (char - 0xd800) * 0x400 + nextChar - 0xdc00 + 0x10000, - ); - // Advance index one extra since we already used that char here. - i++; - continue; - } - } - escapeSeq = ESCAPE_SEQUENCES[char]; - result += !escapeSeq && isPrintable(char) - ? string[i] - : escapeSeq || encodeHex(char); - } - - return result; -} - -// Pre-conditions: string is valid for a block scalar, 1 <= indentPerLevel <= 9. -function blockHeader(string: string, indentPerLevel: number): string { - const indentIndicator = needIndentIndicator(string) - ? String(indentPerLevel) - : ""; - - // note the special case: the string '\n' counts as a "trailing" empty line. - 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`; -} - -// Note: line breaking/folding is implemented for only the folded style. -// NB. We drop the last trailing newline (if any) of a returned block scalar -// since the dumper adds its own newline. This always works: -// • No ending newline => unaffected; already using strip "-" chomping. -// • Ending newline => removed then restored. -// Importantly, this keeps the "+" chomp indicator from gaining an extra line. -function writeScalar( - state: DumperState, - string: string, - level: number, - iskey: boolean, -): void { - state.dump = ((): string => { - if (string.length === 0) { - return "''"; - } - if ( - !state.noCompatMode && - DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1 - ) { - return `'${string}'`; - } - - const indent = state.indent * Math.max(1, level); // no 0-indent scalars - // As indentation gets deeper, let the width decrease monotonically - // to the lower bound min(state.lineWidth, 40). - // Note that this implies - // state.lineWidth ≤ 40 + state.indent: width is fixed at the lower bound. - // state.lineWidth > 40 + state.indent: width decreases until the lower - // bound. - // This behaves better than a constant minimum width which disallows - // narrower options, or an indent threshold which causes the width - // to suddenly increase. - const lineWidth = state.lineWidth === -1 - ? -1 - : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent); - - // Without knowing if keys are implicit/explicit, - // assume implicit for safety. - const singleLineOnly = iskey || - // No block styles in flow mode. - (state.flowLevel > -1 && level >= state.flowLevel); - function testAmbiguity(str: string): boolean { - 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: DumperState, - level: number, - object: Any, -): void { - let _result = ""; - const _tag = state.tag; - - for (let index = 0, length = object.length; index < length; index += 1) { - // Write only valid elements. - // eslint-disable-next-line @typescript-eslint/no-use-before-define - 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: DumperState, - level: number, - object: Any, - compact = false, -): void { - let _result = ""; - const _tag = state.tag; - - for (let index = 0, length = object.length; index < length; index += 1) { - // Write only valid elements. - // eslint-disable-next-line @typescript-eslint/no-use-before-define - if (writeNode(state, level + 1, object[index], true, true)) { - if (!compact || index !== 0) { - _result += generateNextLine(state, level); - } - - if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { - _result += "-"; - } else { - _result += "- "; - } - - _result += state.dump; - } - } - - state.tag = _tag; - state.dump = _result || "[]"; // Empty sequence if no valid values. -} - -function writeFlowMapping( - state: DumperState, - level: number, - object: Any, -): void { - let _result = ""; - const _tag = state.tag, - objectKeyList = Object.keys(object); - - let pairBuffer: string, objectKey: string, objectValue: Any; - for ( - let index = 0, length = objectKeyList.length; - index < length; - index += 1 - ) { - pairBuffer = state.condenseFlow ? '"' : ""; - - if (index !== 0) pairBuffer += ", "; - - objectKey = objectKeyList[index]; - objectValue = object[objectKey]; - - // eslint-disable-next-line @typescript-eslint/no-use-before-define - if (!writeNode(state, level, objectKey, false, false)) { - continue; // Skip this pair because of invalid key; - } - - if (state.dump.length > 1024) pairBuffer += "? "; - - pairBuffer += `${state.dump}${state.condenseFlow ? '"' : ""}:${ - state.condenseFlow ? "" : " " - }`; - - // eslint-disable-next-line @typescript-eslint/no-use-before-define - if (!writeNode(state, level, objectValue, false, false)) { - continue; // Skip this pair because of invalid value. - } - - pairBuffer += state.dump; - - // Both key and value are valid. - _result += pairBuffer; - } - - state.tag = _tag; - state.dump = `{${_result}}`; -} - -function writeBlockMapping( - state: DumperState, - level: number, - object: Any, - compact = false, -): void { - const _tag = state.tag, - objectKeyList = Object.keys(object); - let _result = ""; - - // Allow sorting keys so that the output file is deterministic - if (state.sortKeys === true) { - // Default sorting - objectKeyList.sort(); - } else if (typeof state.sortKeys === "function") { - // Custom sort function - objectKeyList.sort(state.sortKeys); - } else if (state.sortKeys) { - // Something is wrong - throw new YAMLError("sortKeys must be a boolean or a function"); - } - - let pairBuffer = "", - objectKey: string, - objectValue: Any, - explicitPair: boolean; - 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]; - - // eslint-disable-next-line @typescript-eslint/no-use-before-define - if (!writeNode(state, level + 1, objectKey, true, true, true)) { - continue; // Skip this pair because of invalid key. - } - - explicitPair = (state.tag !== null && state.tag !== "?") || - (state.dump && state.dump.length > 1024); - - if (explicitPair) { - if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { - pairBuffer += "?"; - } else { - pairBuffer += "? "; - } - } - - pairBuffer += state.dump; - - if (explicitPair) { - pairBuffer += generateNextLine(state, level); - } - - // eslint-disable-next-line @typescript-eslint/no-use-before-define - if (!writeNode(state, level + 1, objectValue, true, explicitPair)) { - continue; // Skip this pair because of invalid value. - } - - if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { - pairBuffer += ":"; - } else { - pairBuffer += ": "; - } - - pairBuffer += state.dump; - - // Both key and value are valid. - _result += pairBuffer; - } - - state.tag = _tag; - state.dump = _result || "{}"; // Empty mapping if no valid pairs. -} - -function detectType( - state: DumperState, - object: Any, - explicit = false, -): boolean { - const typeList = explicit ? state.explicitTypes : state.implicitTypes; - - let type: Type; - let style: StyleVariant; - let _result: string; - 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 (_toString.call(type.represent) === "[object Function]") { - _result = (type.represent as RepresentFn)(object, style); - } else if (_hasOwnProperty.call(type.represent, style)) { - _result = (type.represent as ArrayObject<RepresentFn>)[style]( - object, - style, - ); - } else { - throw new YAMLError( - `!<${type.tag}> tag resolver accepts not "${style}" style`, - ); - } - - state.dump = _result; - } - - return true; - } - } - - return false; -} - -// Serializes `object` and writes it to global `result`. -// Returns true on success, or false on invalid object. -// -function writeNode( - state: DumperState, - level: number, - object: Any, - block: boolean, - compact: boolean, - iskey = false, -): boolean { - state.tag = null; - state.dump = object; - - if (!detectType(state, object, false)) { - detectType(state, object, true); - } - - const type = _toString.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: Any, - objects: Any[], - duplicatesIndexes: number[], -): void { - 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 idx = 0, length = objectKeyList.length; - idx < length; - idx += 1 - ) { - inspectNode(object[objectKeyList[idx]], objects, duplicatesIndexes); - } - } - } - } -} - -function getDuplicateReferences( - object: Record<string, unknown>, - state: DumperState, -): void { - const objects: Any[] = [], - duplicatesIndexes: number[] = []; - - inspectNode(object, objects, duplicatesIndexes); - - const length = duplicatesIndexes.length; - for (let index = 0; index < length; index += 1) { - state.duplicates.push(objects[duplicatesIndexes[index]]); - } - state.usedDuplicates = new Array(length); -} - -export function dump(input: Any, options?: DumperStateOptions): string { - 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 ""; -} diff --git a/std/encoding/_yaml/dumper/dumper_state.ts b/std/encoding/_yaml/dumper/dumper_state.ts deleted file mode 100644 index 6861e7a43..000000000 --- a/std/encoding/_yaml/dumper/dumper_state.ts +++ /dev/null @@ -1,141 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import type { Schema, SchemaDefinition } from "../schema.ts"; -import { State } from "../state.ts"; -import type { StyleVariant, Type } from "../type.ts"; -import type { Any, ArrayObject } from "../utils.ts"; - -const _hasOwnProperty = Object.prototype.hasOwnProperty; - -function compileStyleMap( - schema: Schema, - map?: ArrayObject<StyleVariant> | null, -): ArrayObject<StyleVariant> { - if (typeof map === "undefined" || map === null) return {}; - - let type: Type; - const result: ArrayObject<StyleVariant> = {}; - const keys = Object.keys(map); - let tag: string, style: StyleVariant; - for (let index = 0, length = keys.length; index < length; index += 1) { - tag = keys[index]; - style = String(map[tag]) as StyleVariant; - if (tag.slice(0, 2) === "!!") { - tag = `tag:yaml.org,2002:${tag.slice(2)}`; - } - type = schema.compiledTypeMap.fallback[tag]; - - if ( - type && - typeof type.styleAliases !== "undefined" && - _hasOwnProperty.call(type.styleAliases, style) - ) { - style = type.styleAliases[style]; - } - - result[tag] = style; - } - - return result; -} - -export interface DumperStateOptions { - /** indentation width to use (in spaces). */ - indent?: number; - /** when true, will not add an indentation level to array elements */ - noArrayIndent?: boolean; - /** - * do not throw on invalid types (like function in the safe schema) - * and skip pairs and single values with such types. - */ - skipInvalid?: boolean; - /** - * specifies level of nesting, when to switch from - * block to flow style for collections. -1 means block style everywhere - */ - flowLevel?: number; - /** Each tag may have own set of styles. - "tag" => "style" map. */ - styles?: ArrayObject<StyleVariant> | null; - /** specifies a schema to use. */ - schema?: SchemaDefinition; - /** - * If true, sort keys when dumping YAML in ascending, ASCII character order. - * If a function, use the function to sort the keys. (default: false) - * If a function is specified, the function must return a negative value - * if first argument is less than second argument, zero if they're equal - * and a positive value otherwise. - */ - sortKeys?: boolean | ((a: string, b: string) => number); - /** set max line width. (default: 80) */ - lineWidth?: number; - /** - * if true, don't convert duplicate objects - * into references (default: false) - */ - noRefs?: boolean; - /** - * if true don't try to be compatible with older yaml versions. - * Currently: don't quote "yes", "no" and so on, - * as required for YAML 1.1 (default: false) - */ - noCompatMode?: boolean; - /** - * if true flow sequences will be condensed, omitting the - * space between `key: value` or `a, b`. Eg. `'[a,b]'` or `{a:{b:c}}`. - * Can be useful when using yaml for pretty URL query params - * as spaces are %-encoded. (default: false). - */ - condenseFlow?: boolean; -} - -export class DumperState extends State { - public indent: number; - public noArrayIndent: boolean; - public skipInvalid: boolean; - public flowLevel: number; - public sortKeys: boolean | ((a: Any, b: Any) => number); - public lineWidth: number; - public noRefs: boolean; - public noCompatMode: boolean; - public condenseFlow: boolean; - public implicitTypes: Type[]; - public explicitTypes: Type[]; - public tag: string | null = null; - public result = ""; - public duplicates: Any[] = []; - public usedDuplicates: Any[] = []; // changed from null to [] - public styleMap: ArrayObject<StyleVariant>; - public dump: Any; - - constructor({ - schema, - indent = 2, - noArrayIndent = false, - skipInvalid = false, - flowLevel = -1, - styles = null, - sortKeys = false, - lineWidth = 80, - noRefs = false, - noCompatMode = false, - condenseFlow = false, - }: DumperStateOptions) { - super(schema); - this.indent = Math.max(1, indent); - this.noArrayIndent = noArrayIndent; - this.skipInvalid = skipInvalid; - this.flowLevel = flowLevel; - this.styleMap = compileStyleMap(this.schema as Schema, styles); - this.sortKeys = sortKeys; - this.lineWidth = lineWidth; - this.noRefs = noRefs; - this.noCompatMode = noCompatMode; - this.condenseFlow = condenseFlow; - - this.implicitTypes = (this.schema as Schema).compiledImplicit; - this.explicitTypes = (this.schema as Schema).compiledExplicit; - } -} diff --git a/std/encoding/_yaml/error.ts b/std/encoding/_yaml/error.ts deleted file mode 100644 index 6b1e359b6..000000000 --- a/std/encoding/_yaml/error.ts +++ /dev/null @@ -1,20 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import type { Mark } from "./mark.ts"; - -export class YAMLError extends Error { - constructor( - message = "(unknown reason)", - protected mark: Mark | string = "", - ) { - super(`${message} ${mark}`); - this.name = this.constructor.name; - } - - public toString(_compact: boolean): string { - return `${this.name}: ${this.message} ${this.mark}`; - } -} diff --git a/std/encoding/_yaml/example/dump.ts b/std/encoding/_yaml/example/dump.ts deleted file mode 100644 index 3304474f2..000000000 --- a/std/encoding/_yaml/example/dump.ts +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -import { stringify } from "../../yaml.ts"; - -console.log( - stringify({ - foo: { - bar: true, - test: [ - "a", - "b", - { - a: false, - }, - { - a: false, - }, - ], - }, - test: "foobar", - }), -); diff --git a/std/encoding/_yaml/example/inout.ts b/std/encoding/_yaml/example/inout.ts deleted file mode 100644 index fd4e1e6c2..000000000 --- a/std/encoding/_yaml/example/inout.ts +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -import { parse, stringify } from "../../yaml.ts"; - -const test = { - foo: { - bar: true, - test: [ - "a", - "b", - { - a: false, - }, - { - a: false, - }, - ], - }, - test: "foobar", -}; - -const string = stringify(test); -if (Deno.inspect(test) === Deno.inspect(parse(string))) { - console.log("In-Out as expected."); -} else { - console.log("Something went wrong."); -} diff --git a/std/encoding/_yaml/example/parse.ts b/std/encoding/_yaml/example/parse.ts deleted file mode 100644 index b4da86aac..000000000 --- a/std/encoding/_yaml/example/parse.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -import { parse } from "../../yaml.ts"; - -const result = parse(` -test: toto -foo: - bar: True - baz: 1 - qux: ~ -`); -console.log(result); - -const expected = '{ test: "toto", foo: { bar: true, baz: 1, qux: null } }'; -if (Deno.inspect(result) === expected) { - console.log("Output is as expected."); -} else { - console.error("Error during parse. Output is not as expect.", expected); -} diff --git a/std/encoding/_yaml/example/sample_document.ts b/std/encoding/_yaml/example/sample_document.ts deleted file mode 100644 index 695744322..000000000 --- a/std/encoding/_yaml/example/sample_document.ts +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -import { parse } from "../../yaml.ts"; - -(() => { - const yml = Deno.readFileSync(`${Deno.cwd()}/example/sample_document.yml`); - - const document = new TextDecoder().decode(yml); - // deno-lint-ignore no-explicit-any - const obj = parse(document) as Record<string, any>; - console.log(obj); - - let i = 0; - for (const o of Object.values(obj)) { - console.log(`======${i}`); - for (const [key, value] of Object.entries(o)) { - console.log(key, value); - } - i++; - } -})(); diff --git a/std/encoding/_yaml/example/sample_document.yml b/std/encoding/_yaml/example/sample_document.yml deleted file mode 100644 index 1f3c2eb3e..000000000 --- a/std/encoding/_yaml/example/sample_document.yml +++ /dev/null @@ -1,197 +0,0 @@ ---- -# Collection Types ############################################################# -################################################################################ - -# http://yaml.org/type/map.html -----------------------------------------------# - -map: - # Unordered set of key: value pairs. - Block style: !!map - Clark : Evans - Ingy : döt Net - Oren : Ben-Kiki - Flow style: !!map { Clark: Evans, Ingy: döt Net, Oren: Ben-Kiki } - -# http://yaml.org/type/omap.html ----------------------------------------------# - -omap: - # Explicitly typed ordered map (dictionary). - Bestiary: !!omap - - aardvark: African pig-like ant eater. Ugly. - - anteater: South-American ant eater. Two species. - - anaconda: South-American constrictor snake. Scaly. - # Etc. - # Flow style - Numbers: !!omap [ one: 1, two: 2, three : 3 ] - -# http://yaml.org/type/pairs.html ---------------------------------------------# - -pairs: - # Explicitly typed pairs. - Block tasks: !!pairs - - meeting: with team. - - meeting: with boss. - - break: lunch. - - meeting: with client. - Flow tasks: !!pairs [ meeting: with team, meeting: with boss ] - -# http://yaml.org/type/set.html -----------------------------------------------# - -set: - # Explicitly typed set. - baseball players: !!set - ? Mark McGwire - ? Sammy Sosa - ? Ken Griffey - # Flow style - baseball teams: !!set { Boston Red Sox, Detroit Tigers, New York Yankees } - -# http://yaml.org/type/seq.html -----------------------------------------------# - -seq: - # Ordered sequence of nodes - Block style: !!seq - - Mercury # Rotates - no light/dark sides. - - Venus # Deadliest. Aptly named. - - Earth # Mostly dirt. - - Mars # Seems empty. - - Jupiter # The king. - - Saturn # Pretty. - - Uranus # Where the sun hardly shines. - - Neptune # Boring. No rings. - - Pluto # You call this a planet? - Flow style: !!seq [ Mercury, Venus, Earth, Mars, # Rocks - Jupiter, Saturn, Uranus, Neptune, # Gas - Pluto ] # Overrated - - -# Scalar Types ################################################################# -################################################################################ - -# http://yaml.org/type/binary.html --------------------------------------------# - -binary: - canonical: !!binary "\ - R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5\ - OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+\ - +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC\ - AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=" - generic: !!binary | - R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5 - OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+ - +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC - AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs= - description: - The binary value above is a tiny arrow encoded as a gif image. - -# http://yaml.org/type/bool.html ----------------------------------------------# - -bool: - - true - - True - - TRUE - - false - - False - - FALSE - -# http://yaml.org/type/float.html ---------------------------------------------# - -float: - canonical: 6.8523015e+5 - exponential: 685.230_15e+03 - fixed: 685_230.15 - sexagesimal: 190:20:30.15 - negative infinity: -.inf - not a number: .NaN - -# http://yaml.org/type/int.html -----------------------------------------------# - -int: - canonical: 685230 - decimal: +685_230 - octal: 02472256 - hexadecimal: 0x_0A_74_AE - binary: 0b1010_0111_0100_1010_1110 - sexagesimal: 190:20:30 - -# http://yaml.org/type/merge.html ---------------------------------------------# - -merge: - - &CENTER { x: 1, y: 2 } - - &LEFT { x: 0, y: 2 } - - &BIG { r: 10 } - - &SMALL { r: 1 } - - # All the following maps are equal: - - - # Explicit keys - x: 1 - y: 2 - r: 10 - label: nothing - - - # Merge one map - << : *CENTER - r: 10 - label: center - - - # Merge multiple maps - << : [ *CENTER, *BIG ] - label: center/big - - - # Override - << : [ *BIG, *LEFT, *SMALL ] - x: 1 - label: big/left/small - -# http://yaml.org/type/null.html ----------------------------------------------# - -null: - # This mapping has four keys, - # one has a value. - empty: - canonical: ~ - english: null - ~: null key - # This sequence has five - # entries, two have values. - sparse: - - ~ - - 2nd entry - - - - 4th entry - - Null - -# http://yaml.org/type/str.html -----------------------------------------------# - -string: abcd - -# http://yaml.org/type/timestamp.html -----------------------------------------# - -timestamp: - canonical: 2001-12-15T02:59:43.1Z - valid iso8601: 2001-12-14t21:59:43.10-05:00 - space separated: 2001-12-14 21:59:43.10 -5 - no time zone (Z): 2001-12-15 2:59:43.10 - date (00:00:00Z): 2002-12-14 - - -# JavaScript Specific Types #################################################### -################################################################################ - -# https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/RegExp - -# regexp: -# simple: !!js/regexp foobar -# modifiers: !!js/regexp /foobar/mi - -# https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/undefined - -# undefined: !!js/undefined ~ - -# https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function - -# function: !!js/function > -# function foobar() { -# return 'Wow! JS-YAML Rocks!'; -# } diff --git a/std/encoding/_yaml/loader/loader.ts b/std/encoding/_yaml/loader/loader.ts deleted file mode 100644 index 322f5ce0d..000000000 --- a/std/encoding/_yaml/loader/loader.ts +++ /dev/null @@ -1,1798 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { YAMLError } from "../error.ts"; -import { Mark } from "../mark.ts"; -import type { Type } from "../type.ts"; -import * as common from "../utils.ts"; -import { LoaderState, LoaderStateOptions, ResultType } from "./loader_state.ts"; - -type Any = common.Any; -type ArrayObject<T = Any> = common.ArrayObject<T>; - -const _hasOwnProperty = Object.prototype.hasOwnProperty; - -const CONTEXT_FLOW_IN = 1; -const CONTEXT_FLOW_OUT = 2; -const CONTEXT_BLOCK_IN = 3; -const CONTEXT_BLOCK_OUT = 4; - -const CHOMPING_CLIP = 1; -const CHOMPING_STRIP = 2; -const CHOMPING_KEEP = 3; - -const PATTERN_NON_PRINTABLE = - // deno-lint-ignore no-control-regex - /[\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: unknown): string { - return Object.prototype.toString.call(obj); -} - -function isEOL(c: number): boolean { - return c === 0x0a || /* LF */ c === 0x0d /* CR */; -} - -function isWhiteSpace(c: number): boolean { - return c === 0x09 || /* Tab */ c === 0x20 /* Space */; -} - -function isWsOrEol(c: number): boolean { - return ( - c === 0x09 /* Tab */ || - c === 0x20 /* Space */ || - c === 0x0a /* LF */ || - c === 0x0d /* CR */ - ); -} - -function isFlowIndicator(c: number): boolean { - return ( - c === 0x2c /* , */ || - c === 0x5b /* [ */ || - c === 0x5d /* ] */ || - c === 0x7b /* { */ || - c === 0x7d /* } */ - ); -} - -function fromHexCode(c: number): number { - if (0x30 <= /* 0 */ c && c <= 0x39 /* 9 */) { - return c - 0x30; - } - - const lc = c | 0x20; - - if (0x61 <= /* a */ lc && lc <= 0x66 /* f */) { - return lc - 0x61 + 10; - } - - return -1; -} - -function escapedHexLen(c: number): number { - if (c === 0x78 /* x */) { - return 2; - } - if (c === 0x75 /* u */) { - return 4; - } - if (c === 0x55 /* U */) { - return 8; - } - return 0; -} - -function fromDecimalCode(c: number): number { - if (0x30 <= /* 0 */ c && c <= 0x39 /* 9 */) { - return c - 0x30; - } - - return -1; -} - -function simpleEscapeSequence(c: number): string { - /* eslint:disable:prettier */ - return c === 0x30 /* 0 */ - ? "\x00" - : c === 0x61 /* a */ - ? "\x07" - : c === 0x62 /* b */ - ? "\x08" - : c === 0x74 /* t */ - ? "\x09" - : c === 0x09 /* Tab */ - ? "\x09" - : c === 0x6e /* n */ - ? "\x0A" - : c === 0x76 /* v */ - ? "\x0B" - : c === 0x66 /* f */ - ? "\x0C" - : c === 0x72 /* r */ - ? "\x0D" - : c === 0x65 /* e */ - ? "\x1B" - : c === 0x20 /* Space */ - ? " " - : c === 0x22 /* " */ - ? "\x22" - : c === 0x2f /* / */ - ? "/" - : c === 0x5c /* \ */ - ? "\x5C" - : c === 0x4e /* N */ - ? "\x85" - : c === 0x5f /* _ */ - ? "\xA0" - : c === 0x4c /* L */ - ? "\u2028" - : c === 0x50 /* P */ - ? "\u2029" - : ""; - /* eslint:enable:prettier */ -} - -function charFromCodepoint(c: number): string { - if (c <= 0xffff) { - return String.fromCharCode(c); - } - // Encode UTF-16 surrogate pair - // https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B010000_to_U.2B10FFFF - return String.fromCharCode( - ((c - 0x010000) >> 10) + 0xd800, - ((c - 0x010000) & 0x03ff) + 0xdc00, - ); -} - -const simpleEscapeCheck = new Array(256); // integer, for fast access -const simpleEscapeMap = new Array(256); -for (let i = 0; i < 256; i++) { - simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0; - simpleEscapeMap[i] = simpleEscapeSequence(i); -} - -function generateError(state: LoaderState, message: string): YAMLError { - return new YAMLError( - message, - new Mark( - state.filename as string, - state.input, - state.position, - state.line, - state.position - state.lineStart, - ), - ); -} - -function throwError(state: LoaderState, message: string): never { - throw generateError(state, message); -} - -function throwWarning(state: LoaderState, message: string): void { - if (state.onWarning) { - state.onWarning.call(null, generateError(state, message)); - } -} - -interface DirectiveHandlers { - [directive: string]: ( - state: LoaderState, - name: string, - ...args: string[] - ) => void; -} - -const directiveHandlers: DirectiveHandlers = { - YAML(state, _name, ...args: string[]) { - 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: string[]): void { - 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 (_hasOwnProperty.call(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: LoaderState, - start: number, - end: number, - checkJson: boolean, -): void { - let result: string; - 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: LoaderState, - destination: ArrayObject, - source: ArrayObject, - overridableKeys: ArrayObject<boolean>, -): void { - if (!common.isObject(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 (!_hasOwnProperty.call(destination, key)) { - destination[key] = (source as ArrayObject)[key]; - overridableKeys[key] = true; - } - } -} - -function storeMappingPair( - state: LoaderState, - result: ArrayObject | null, - overridableKeys: ArrayObject<boolean>, - keyTag: string | null, - keyNode: Any, - valueNode: unknown, - startLine?: number, - startPos?: number, -): ArrayObject { - // The output is a plain object here, so keys can only be strings. - // We need to convert keyNode to a string, but doing so can hang the process - // (deeply nested arrays that explode exponentially using aliases). - 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]"; - } - } - } - - // Avoid code execution in load() via toString property - // (still use its own toString for arrays, timestamps, - // and whatever user schema extensions happen to have @@toStringTag) - 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 index = 0, quantity = valueNode.length; - index < quantity; - index++ - ) { - mergeMappings(state, result, valueNode[index], overridableKeys); - } - } else { - mergeMappings(state, result, valueNode as ArrayObject, overridableKeys); - } - } else { - if ( - !state.json && - !_hasOwnProperty.call(overridableKeys, keyNode) && - _hasOwnProperty.call(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: LoaderState): void { - const ch = state.input.charCodeAt(state.position); - - if (ch === 0x0a /* LF */) { - state.position++; - } else if (ch === 0x0d /* CR */) { - state.position++; - if (state.input.charCodeAt(state.position) === 0x0a /* LF */) { - state.position++; - } - } else { - return throwError(state, "a line break is expected"); - } - - state.line += 1; - state.lineStart = state.position; -} - -function skipSeparationSpace( - state: LoaderState, - allowComments: boolean, - checkIndent: number, -): number { - 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 && /* LF */ ch !== 0x0d && /* CR */ ch !== 0); - } - - if (isEOL(ch)) { - readLineBreak(state); - - ch = state.input.charCodeAt(state.position); - lineBreaks++; - state.lineIndent = 0; - - while (ch === 0x20 /* Space */) { - 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: LoaderState): boolean { - let _position = state.position; - let ch = state.input.charCodeAt(_position); - - // Condition state.position === state.lineStart is tested - // in parent on each call, for efficiency. No needs to test here again. - 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: LoaderState, count: number): void { - if (count === 1) { - state.result += " "; - } else if (count > 1) { - state.result += common.repeat("\n", count - 1); - } -} - -function readPlainScalar( - state: LoaderState, - nodeIndent: number, - withinFlowCollection: boolean, -): boolean { - 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: number; - 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: number, - 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: LoaderState, - nodeIndent: number, -): boolean { - 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: LoaderState, - nodeIndent: number, -): boolean { - let ch = state.input.charCodeAt(state.position); - - if (ch !== 0x22 /* " */) { - return false; - } - - state.kind = "scalar"; - state.result = ""; - state.position++; - let captureEnd: number, - captureStart = (captureEnd = state.position); - let tmp: number; - 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); - - // TODO(bartlomieju): rework to inline fn with no type cast? - } 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: LoaderState, nodeIndent: number): boolean { - let ch = state.input.charCodeAt(state.position); - let terminator: number; - let isMapping = true; - let result: ResultType = {}; - 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: string | null = (keyNode = valueNode = null), - isExplicitPair: boolean, - isPair = (isExplicitPair = false); - let following = 0, - line = 0; - const overridableKeys: ArrayObject<boolean> = {}; - 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; - // eslint-disable-next-line @typescript-eslint/no-use-before-define - composeNode(state, nodeIndent, CONTEXT_FLOW_IN, 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); - // eslint-disable-next-line @typescript-eslint/no-use-before-define - composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); - valueNode = state.result; - } - - if (isMapping) { - storeMappingPair( - state, - result, - overridableKeys, - keyTag, - keyNode, - valueNode, - ); - } else if (isPair) { - (result as ArrayObject[]).push( - storeMappingPair( - state, - null, - overridableKeys, - keyTag, - keyNode, - valueNode, - ), - ); - } else { - (result as ResultType[]).push(keyNode as ResultType); - } - - 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: LoaderState, nodeIndent: number): boolean { - let chomping = CHOMPING_CLIP, - 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 (CHOMPING_CLIP === 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 /* Space */ - ) { - state.lineIndent++; - ch = state.input.charCodeAt(++state.position); - } - - if (!detectedIndent && state.lineIndent > textIndent) { - textIndent = state.lineIndent; - } - - if (isEOL(ch)) { - emptyLines++; - continue; - } - - // End of the scalar. - if (state.lineIndent < textIndent) { - // Perform the chomping. - if (chomping === CHOMPING_KEEP) { - state.result += common.repeat( - "\n", - didReadContent ? 1 + emptyLines : emptyLines, - ); - } else if (chomping === CHOMPING_CLIP) { - if (didReadContent) { - // i.e. only if the scalar is not empty. - state.result += "\n"; - } - } - - // Break this `while` cycle and go to the function's epilogue. - break; - } - - // Folded style: use fancy rules to handle line breaks. - if (folding) { - // Lines starting with white space characters (more-indented lines) are not folded. - if (isWhiteSpace(ch)) { - atMoreIndented = true; - // except for the first content line (cf. Example 8.1) - state.result += common.repeat( - "\n", - didReadContent ? 1 + emptyLines : emptyLines, - ); - - // End of more-indented block. - } else if (atMoreIndented) { - atMoreIndented = false; - state.result += common.repeat("\n", emptyLines + 1); - - // Just one line break - perceive as the same line. - } else if (emptyLines === 0) { - if (didReadContent) { - // i.e. only if we have already read some scalar content. - state.result += " "; - } - - // Several line breaks - perceive as different lines. - } else { - state.result += common.repeat("\n", emptyLines); - } - - // Literal style: just add exact number of line breaks between content lines. - } else { - // Keep all line breaks except the header line break. - state.result += common.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: LoaderState, nodeIndent: number): boolean { - let line: number, - following: number, - detected = false, - ch: number; - const tag = state.tag, - anchor = state.anchor, - result: unknown[] = []; - - 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; - // eslint-disable-next-line @typescript-eslint/no-use-before-define - composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, 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: LoaderState, - nodeIndent: number, - flowIndent: number, -): boolean { - const tag = state.tag, - anchor = state.anchor, - result = {}, - overridableKeys = {}; - let following: number, - allowCompact = false, - line: number, - pos: number, - keyTag = null, - keyNode = null, - valueNode = null, - atExplicitKey = false, - detected = false, - ch: number; - - 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; // Save the current line. - pos = state.position; - - // - // Explicit notation case. There are two separate blocks: - // first for the key (denoted by "?") and second for the value (denoted by ":") - // - if ((ch === 0x3f || /* ? */ ch === 0x3a) && /* : */ isWsOrEol(following)) { - if (ch === 0x3f /* ? */) { - if (atExplicitKey) { - storeMappingPair( - state, - result, - overridableKeys, - keyTag as string, - keyNode, - null, - ); - keyTag = keyNode = valueNode = null; - } - - detected = true; - atExplicitKey = true; - allowCompact = true; - } else if (atExplicitKey) { - // i.e. 0x3A/* : */ === character after the explicit key. - 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; - - // - // Implicit notation case. Flow-style node as the key first, then ":", and the value. - // - // eslint-disable-next-line @typescript-eslint/no-use-before-define - } else if (composeNode(state, flowIndent, CONTEXT_FLOW_OUT, 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 as string, - 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; // Keep the result of `composeNode`. - } - } 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; // Keep the result of `composeNode`. - } - } else { - break; // Reading is done. Go to the epilogue. - } - - // - // Common reading code for both explicit and implicit notations. - // - if (state.line === line || state.lineIndent > nodeIndent) { - if ( - // eslint-disable-next-line @typescript-eslint/no-use-before-define - composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact) - ) { - if (atExplicitKey) { - keyNode = state.result; - } else { - valueNode = state.result; - } - } - - if (!atExplicitKey) { - storeMappingPair( - state, - result, - overridableKeys, - keyTag as string, - 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; - } - } - - // - // Epilogue. - // - - // Special case: last mapping's node contains only the key in explicit notation. - if (atExplicitKey) { - storeMappingPair( - state, - result, - overridableKeys, - keyTag as string, - keyNode, - null, - ); - } - - // Expose the resulting mapping. - if (detected) { - state.tag = tag; - state.anchor = anchor; - state.kind = "mapping"; - state.result = result; - } - - return detected; -} - -function readTagProperty(state: LoaderState): boolean { - let position: number, - isVerbatim = false, - isNamed = false, - tagHandle = "", - tagName: string, - ch: number; - - 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" && - _hasOwnProperty.call(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: LoaderState): boolean { - 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: LoaderState): boolean { - 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" && - !Object.prototype.hasOwnProperty.call(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: LoaderState, - parentIndent: number, - nodeContext: number, - allowToSeek: boolean, - allowCompact: boolean, -): boolean { - let allowBlockScalars: boolean, - allowBlockCollections: boolean, - indentStatus = 1, // 1: this>parent, 0: this=parent, -1: this<parent - atNewLine = false, - hasContent = false, - type: Type, - flowIndent: number, - blockIndent: number; - - 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 || CONTEXT_BLOCK_OUT === nodeContext) { - const cond = CONTEXT_FLOW_IN === nodeContext || - CONTEXT_FLOW_OUT === 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, CONTEXT_FLOW_IN === 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) { - // Special case: block sequences are allowed to have same indentation level as the parent. - // http://www.yaml.org/spec/1.2/spec.html#id2799784 - 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]; - - // Implicit resolving is not allowed for non-scalar types, and '?' - // non-specific tag is only assigned to plain scalars. So, it isn't - // needed to check for 'kind' conformity. - - if (type.resolve(state.result)) { - // `state.result` updated in resolver if matched - 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 ( - _hasOwnProperty.call(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)) { - // `state.result` updated in resolver if matched - 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: LoaderState): void { - const documentStart = state.position; - let position: number, - directiveName: string, - directiveArgs: string[], - hasDirectives = false, - ch: number; - - 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 (_hasOwnProperty.call(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, CONTEXT_BLOCK_OUT, 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: string, options?: LoaderStateOptions): unknown[] { - input = String(input); - options = options || {}; - - if (input.length !== 0) { - // Add tailing `\n` if not exists - if ( - input.charCodeAt(input.length - 1) !== 0x0a /* LF */ && - input.charCodeAt(input.length - 1) !== 0x0d /* CR */ - ) { - input += "\n"; - } - - // Strip BOM - if (input.charCodeAt(0) === 0xfeff) { - input = input.slice(1); - } - } - - const state = new LoaderState(input, options); - - // Use 0 as string terminator. That significantly simplifies bounds check. - state.input += "\0"; - - while (state.input.charCodeAt(state.position) === 0x20 /* Space */) { - state.lineIndent += 1; - state.position += 1; - } - - while (state.position < state.length - 1) { - readDocument(state); - } - - return state.documents; -} - -export type CbFunction = (doc: unknown) => void; -function isCbFunction(fn: unknown): fn is CbFunction { - return typeof fn === "function"; -} - -export function loadAll<T extends CbFunction | LoaderStateOptions>( - input: string, - iteratorOrOption?: T, - options?: LoaderStateOptions, -): T extends CbFunction ? void : unknown[] { - if (!isCbFunction(iteratorOrOption)) { - return loadDocuments(input, iteratorOrOption as LoaderStateOptions) as Any; - } - - const documents = loadDocuments(input, options); - const iterator = iteratorOrOption; - for (let index = 0, length = documents.length; index < length; index++) { - iterator(documents[index]); - } - - return void 0 as Any; -} - -export function load(input: string, options?: LoaderStateOptions): unknown { - 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", - ); -} diff --git a/std/encoding/_yaml/loader/loader_state.ts b/std/encoding/_yaml/loader/loader_state.ts deleted file mode 100644 index b5ec77680..000000000 --- a/std/encoding/_yaml/loader/loader_state.ts +++ /dev/null @@ -1,75 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import type { YAMLError } from "../error.ts"; -import type { Schema, SchemaDefinition, TypeMap } from "../schema.ts"; -import { State } from "../state.ts"; -import type { Type } from "../type.ts"; -import type { Any, ArrayObject } from "../utils.ts"; - -export interface LoaderStateOptions { - legacy?: boolean; - listener?: ((...args: Any[]) => void) | null; - /** string to be used as a file path in error/warning messages. */ - filename?: string; - /** specifies a schema to use. */ - schema?: SchemaDefinition; - /** compatibility with JSON.parse behaviour. */ - json?: boolean; - /** function to call on warning messages. */ - onWarning?(this: null, e?: YAMLError): void; -} - -// deno-lint-ignore no-explicit-any -export type ResultType = any[] | Record<string, any> | string; - -export class LoaderState extends State { - public documents: Any[] = []; - public length: number; - public lineIndent = 0; - public lineStart = 0; - public position = 0; - public line = 0; - public filename?: string; - public onWarning?: (...args: Any[]) => void; - public legacy: boolean; - public json: boolean; - public listener?: ((...args: Any[]) => void) | null; - public implicitTypes: Type[]; - public typeMap: TypeMap; - - public version?: string | null; - public checkLineBreaks?: boolean; - public tagMap?: ArrayObject; - public anchorMap?: ArrayObject; - public tag?: string | null; - public anchor?: string | null; - public kind?: string | null; - public result: ResultType | null = ""; - - constructor( - public input: string, - { - filename, - schema, - onWarning, - legacy = false, - json = false, - listener = null, - }: LoaderStateOptions, - ) { - super(schema); - this.filename = filename; - this.onWarning = onWarning; - this.legacy = legacy; - this.json = json; - this.listener = listener; - - this.implicitTypes = (this.schema as Schema).compiledImplicit; - this.typeMap = (this.schema as Schema).compiledTypeMap; - - this.length = input.length; - } -} diff --git a/std/encoding/_yaml/mark.ts b/std/encoding/_yaml/mark.ts deleted file mode 100644 index 399d6a7f3..000000000 --- a/std/encoding/_yaml/mark.ts +++ /dev/null @@ -1,79 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { repeat } from "./utils.ts"; - -export class Mark { - constructor( - public name: string, - public buffer: string, - public position: number, - public line: number, - public column: number, - ) {} - - public getSnippet(indent = 4, maxLength = 75): string | null { - 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, - ) - }^`; - } - - public toString(compact?: boolean): string { - 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; - } -} diff --git a/std/encoding/_yaml/parse.ts b/std/encoding/_yaml/parse.ts deleted file mode 100644 index a6469f799..000000000 --- a/std/encoding/_yaml/parse.ts +++ /dev/null @@ -1,32 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { CbFunction, load, loadAll } from "./loader/loader.ts"; -import type { LoaderStateOptions } from "./loader/loader_state.ts"; - -export type ParseOptions = LoaderStateOptions; - -/** - * Parses `content` as single YAML document. - * - * Returns a JavaScript object or throws `YAMLException` on error. - * By default, does not support regexps, functions and undefined. This method is safe for untrusted data. - * - */ -export function parse(content: string, options?: ParseOptions): unknown { - return load(content, options); -} - -/** - * Same as `parse()`, but understands multi-document sources. - * Applies iterator to each document if specified, or returns array of documents. - */ -export function parseAll( - content: string, - iterator?: CbFunction, - options?: ParseOptions, -): unknown { - return loadAll(content, iterator, options); -} diff --git a/std/encoding/_yaml/parse_test.ts b/std/encoding/_yaml/parse_test.ts deleted file mode 100644 index e810637cb..000000000 --- a/std/encoding/_yaml/parse_test.ts +++ /dev/null @@ -1,56 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { parse, parseAll } from "./parse.ts"; -import { assertEquals } from "../../testing/asserts.ts"; - -Deno.test({ - name: "`parse` parses single document yaml string", - fn(): void { - const yaml = ` - test: toto - foo: - bar: True - baz: 1 - qux: ~ - `; - - const expected = { test: "toto", foo: { bar: true, baz: 1, qux: null } }; - - assertEquals(parse(yaml), expected); - }, -}); - -Deno.test({ - name: "`parseAll` parses the yaml string with multiple documents", - fn(): void { - const yaml = ` ---- -id: 1 -name: Alice ---- -id: 2 -name: Bob ---- -id: 3 -name: Eve - `; - const expected = [ - { - id: 1, - name: "Alice", - }, - { - id: 2, - name: "Bob", - }, - { - id: 3, - name: "Eve", - }, - ]; - assertEquals(parseAll(yaml), expected); - }, -}); diff --git a/std/encoding/_yaml/schema.ts b/std/encoding/_yaml/schema.ts deleted file mode 100644 index 512f9f643..000000000 --- a/std/encoding/_yaml/schema.ts +++ /dev/null @@ -1,101 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { YAMLError } from "./error.ts"; -import type { KindType, Type } from "./type.ts"; -import type { Any, ArrayObject } from "./utils.ts"; - -function compileList( - schema: Schema, - name: "implicit" | "explicit", - result: Type[], -): Type[] { - const exclude: number[] = []; - - 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): unknown => !exclude.includes(index)); -} - -export type TypeMap = { [k in KindType | "fallback"]: ArrayObject<Type> }; -function compileMap(...typesList: Type[][]): TypeMap { - const result: TypeMap = { - 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; -} - -export class Schema implements SchemaDefinition { - public static SCHEMA_DEFAULT?: Schema; - - public implicit: Type[]; - public explicit: Type[]; - public include: Schema[]; - - public compiledImplicit: Type[]; - public compiledExplicit: Type[]; - public compiledTypeMap: TypeMap; - - constructor(definition: SchemaDefinition) { - 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( - // eslint-disable-next-line max-len - "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, - ); - } - - public static create(): void {} -} - -export interface SchemaDefinition { - implicit?: Any[]; - explicit?: Type[]; - include?: Schema[]; -} diff --git a/std/encoding/_yaml/schema/core.ts b/std/encoding/_yaml/schema/core.ts deleted file mode 100644 index ad95f7330..000000000 --- a/std/encoding/_yaml/schema/core.ts +++ /dev/null @@ -1,13 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { Schema } from "../schema.ts"; -import { json } from "./json.ts"; - -// Standard YAML's Core schema. -// http://www.yaml.org/spec/1.2/spec.html#id2804923 -export const core = new Schema({ - include: [json], -}); diff --git a/std/encoding/_yaml/schema/default.ts b/std/encoding/_yaml/schema/default.ts deleted file mode 100644 index 60b6d18ad..000000000 --- a/std/encoding/_yaml/schema/default.ts +++ /dev/null @@ -1,16 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { Schema } from "../schema.ts"; -import { binary, merge, omap, pairs, set, timestamp } from "../type/mod.ts"; -import { core } from "./core.ts"; - -// JS-YAML's default schema for `safeLoad` function. -// It is not described in the YAML specification. -export const def = new Schema({ - explicit: [binary, omap, pairs, set], - implicit: [timestamp, merge], - include: [core], -}); diff --git a/std/encoding/_yaml/schema/failsafe.ts b/std/encoding/_yaml/schema/failsafe.ts deleted file mode 100644 index c44e3c567..000000000 --- a/std/encoding/_yaml/schema/failsafe.ts +++ /dev/null @@ -1,13 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { Schema } from "../schema.ts"; -import { map, seq, str } from "../type/mod.ts"; - -// Standard YAML's Failsafe schema. -// http://www.yaml.org/spec/1.2/spec.html#id2802346 -export const failsafe = new Schema({ - explicit: [str, seq, map], -}); diff --git a/std/encoding/_yaml/schema/json.ts b/std/encoding/_yaml/schema/json.ts deleted file mode 100644 index 0d7c2567f..000000000 --- a/std/encoding/_yaml/schema/json.ts +++ /dev/null @@ -1,15 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { Schema } from "../schema.ts"; -import { bool, float, int, nil } from "../type/mod.ts"; -import { failsafe } from "./failsafe.ts"; - -// Standard YAML's JSON schema. -// http://www.yaml.org/spec/1.2/spec.html#id2803231 -export const json = new Schema({ - implicit: [nil, bool, int, float], - include: [failsafe], -}); diff --git a/std/encoding/_yaml/schema/mod.ts b/std/encoding/_yaml/schema/mod.ts deleted file mode 100644 index a12075feb..000000000 --- a/std/encoding/_yaml/schema/mod.ts +++ /dev/null @@ -1,9 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -export { core as CORE_SCHEMA } from "./core.ts"; -export { def as DEFAULT_SCHEMA } from "./default.ts"; -export { failsafe as FAILSAFE_SCHEMA } from "./failsafe.ts"; -export { json as JSON_SCHEMA } from "./json.ts"; diff --git a/std/encoding/_yaml/state.ts b/std/encoding/_yaml/state.ts deleted file mode 100644 index 85cd91118..000000000 --- a/std/encoding/_yaml/state.ts +++ /dev/null @@ -1,11 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import type { SchemaDefinition } from "./schema.ts"; -import { DEFAULT_SCHEMA } from "./schema/mod.ts"; - -export abstract class State { - constructor(public schema: SchemaDefinition = DEFAULT_SCHEMA) {} -} diff --git a/std/encoding/_yaml/stringify.ts b/std/encoding/_yaml/stringify.ts deleted file mode 100644 index ea43cdfef..000000000 --- a/std/encoding/_yaml/stringify.ts +++ /dev/null @@ -1,21 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { dump } from "./dumper/dumper.ts"; -import type { DumperStateOptions } from "./dumper/dumper_state.ts"; - -export type DumpOptions = DumperStateOptions; - -/** - * Serializes `object` as a YAML document. - * - * You can disable exceptions by setting the skipInvalid option to true. - */ -export function stringify( - obj: Record<string, unknown>, - options?: DumpOptions, -): string { - return dump(obj, options); -} diff --git a/std/encoding/_yaml/stringify_test.ts b/std/encoding/_yaml/stringify_test.ts deleted file mode 100644 index 03a7d8f3d..000000000 --- a/std/encoding/_yaml/stringify_test.ts +++ /dev/null @@ -1,41 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { assertEquals } from "../../testing/asserts.ts"; -import { stringify } from "./stringify.ts"; - -Deno.test({ - name: "stringified correctly", - fn(): void { - const FIXTURE = { - foo: { - bar: true, - test: [ - "a", - "b", - { - a: false, - }, - { - a: false, - }, - ], - }, - test: "foobar", - }; - - const ASSERTS = `foo: - bar: true - test: - - a - - b - - a: false - - a: false -test: foobar -`; - - assertEquals(stringify(FIXTURE), ASSERTS); - }, -}); diff --git a/std/encoding/_yaml/type.ts b/std/encoding/_yaml/type.ts deleted file mode 100644 index e5659bfab..000000000 --- a/std/encoding/_yaml/type.ts +++ /dev/null @@ -1,55 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import type { Any, ArrayObject } from "./utils.ts"; - -export type KindType = "sequence" | "scalar" | "mapping"; -export type StyleVariant = "lowercase" | "uppercase" | "camelcase" | "decimal"; -export type RepresentFn = (data: Any, style?: StyleVariant) => Any; - -const DEFAULT_RESOLVE = (): boolean => true; -const DEFAULT_CONSTRUCT = (data: Any): Any => data; - -interface TypeOptions { - kind: KindType; - resolve?: (data: Any) => boolean; - construct?: (data: string) => Any; - instanceOf?: Any; - predicate?: (data: Record<string, unknown>) => boolean; - represent?: RepresentFn | ArrayObject<RepresentFn>; - defaultStyle?: StyleVariant; - styleAliases?: ArrayObject; -} - -function checkTagFormat(tag: string): string { - return tag; -} - -export class Type { - public tag: string; - public kind: KindType | null = null; - public instanceOf: Any; - public predicate?: (data: Record<string, unknown>) => boolean; - public represent?: RepresentFn | ArrayObject<RepresentFn>; - public defaultStyle?: StyleVariant; - public styleAliases?: ArrayObject; - public loadKind?: KindType; - - constructor(tag: string, options?: TypeOptions) { - 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; - } - } - public resolve: (data?: Any) => boolean = (): boolean => true; - public construct: (data?: Any) => Any = (data): Any => data; -} diff --git a/std/encoding/_yaml/type/binary.ts b/std/encoding/_yaml/type/binary.ts deleted file mode 100644 index 3a7982aa4..000000000 --- a/std/encoding/_yaml/type/binary.ts +++ /dev/null @@ -1,136 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. -import { Type } from "../type.ts"; -import type { Any } from "../utils.ts"; - -// [ 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 Deno.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 Deno.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 deleted file mode 100644 index 3dc714987..000000000 --- a/std/encoding/_yaml/type/bool.ts +++ /dev/null @@ -1,39 +0,0 @@ -// 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-2021 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 deleted file mode 100644 index b4d6a3f3f..000000000 --- a/std/encoding/_yaml/type/float.ts +++ /dev/null @@ -1,125 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { StyleVariant, Type } from "../type.ts"; -import { Any, isNegativeZero } 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 requires 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 deleted file mode 100644 index f166778c5..000000000 --- a/std/encoding/_yaml/type/int.ts +++ /dev/null @@ -1,188 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { Type } from "../type.ts"; -import { Any, isNegativeZero } 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 deleted file mode 100644 index 6457597be..000000000 --- a/std/encoding/_yaml/type/map.ts +++ /dev/null @@ -1,14 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { Type } from "../type.ts"; -import type { 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 deleted file mode 100644 index 598b68ffa..000000000 --- a/std/encoding/_yaml/type/merge.ts +++ /dev/null @@ -1,15 +0,0 @@ -// 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-2021 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 deleted file mode 100644 index 480b1fe61..000000000 --- a/std/encoding/_yaml/type/mod.ts +++ /dev/null @@ -1,18 +0,0 @@ -// 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-2021 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 deleted file mode 100644 index 03a2f6bd6..000000000 --- a/std/encoding/_yaml/type/nil.ts +++ /dev/null @@ -1,45 +0,0 @@ -// 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-2021 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 deleted file mode 100644 index 300debeb8..000000000 --- a/std/encoding/_yaml/type/omap.ts +++ /dev/null @@ -1,46 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { Type } from "../type.ts"; -import type { 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 deleted file mode 100644 index 81664655a..000000000 --- a/std/encoding/_yaml/type/pairs.ts +++ /dev/null @@ -1,49 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { Type } from "../type.ts"; -import type { 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 deleted file mode 100644 index 9679cd516..000000000 --- a/std/encoding/_yaml/type/seq.ts +++ /dev/null @@ -1,14 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { Type } from "../type.ts"; -import type { 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 deleted file mode 100644 index 234951f4d..000000000 --- a/std/encoding/_yaml/type/set.ts +++ /dev/null @@ -1,31 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -import { Type } from "../type.ts"; -import type { 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 deleted file mode 100644 index 053f8b9f7..000000000 --- a/std/encoding/_yaml/type/str.ts +++ /dev/null @@ -1,12 +0,0 @@ -// Ported from js-yaml v3.13.1: -// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da -// Copyright 2018-2021 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 deleted file mode 100644 index 47a797488..000000000 --- a/std/encoding/_yaml/type/timestamp.ts +++ /dev/null @@ -1,96 +0,0 @@ -// 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-2021 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 milli-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, -}); diff --git a/std/encoding/_yaml/utils.ts b/std/encoding/_yaml/utils.ts deleted file mode 100644 index cf18760de..000000000 --- a/std/encoding/_yaml/utils.ts +++ /dev/null @@ -1,80 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -// deno-lint-ignore no-explicit-any -export type Any = any; - -export function isNothing(subject: unknown): subject is never { - return typeof subject === "undefined" || subject === null; -} - -export function isArray(value: unknown): value is Any[] { - return Array.isArray(value); -} - -export function isBoolean(value: unknown): value is boolean { - return typeof value === "boolean" || value instanceof Boolean; -} - -export function isNull(value: unknown): value is null { - return value === null; -} - -export function isNumber(value: unknown): value is number { - return typeof value === "number" || value instanceof Number; -} - -export function isString(value: unknown): value is string { - return typeof value === "string" || value instanceof String; -} - -export function isSymbol(value: unknown): value is symbol { - return typeof value === "symbol"; -} - -export function isUndefined(value: unknown): value is undefined { - return value === undefined; -} - -export function isObject(value: unknown): value is Record<string, unknown> { - return value !== null && typeof value === "object"; -} - -export function isError(e: unknown): boolean { - return e instanceof Error; -} - -export function isFunction(value: unknown): value is () => void { - return typeof value === "function"; -} - -export function isRegExp(value: unknown): value is RegExp { - return value instanceof RegExp; -} - -export function toArray<T>(sequence: T): T | [] | [T] { - if (isArray(sequence)) return sequence; - if (isNothing(sequence)) return []; - - return [sequence]; -} - -export function repeat(str: string, count: number): string { - let result = ""; - - for (let cycle = 0; cycle < count; cycle++) { - result += str; - } - - return result; -} - -export function isNegativeZero(i: number): boolean { - return i === 0 && Number.NEGATIVE_INFINITY === 1 / i; -} - -export interface ArrayObject<T = Any> { - [P: string]: T; -} diff --git a/std/encoding/ascii85.ts b/std/encoding/ascii85.ts deleted file mode 100644 index 877174bfd..000000000 --- a/std/encoding/ascii85.ts +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -// This module is browser compatible. - -export type Ascii85Standard = "Adobe" | "btoa" | "RFC 1924" | "Z85"; -/** - * encoding/decoding options - * @property standard - characterset and delimiter (if supported and used). Defaults to Adobe - * @property delimiter - whether to use a delimiter (if supported) - "<~" and "~>" by default - */ -export interface Ascii85Options { - standard?: Ascii85Standard; - delimiter?: boolean; -} -const rfc1924 = - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"; -const Z85 = - "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#"; -/** - * Encodes a given Uint8Array into ascii85, supports multiple standards - * @param uint8 input to encode - * @param [options] encoding options - * @param [options.standard=Adobe] encoding standard (Adobe, btoa, RFC 1924 or Z85) - * @param [options.delimiter] whether to use a delimiter, if supported by encoding standard - */ -export function encode(uint8: Uint8Array, options?: Ascii85Options): string { - const standard = options?.standard ?? "Adobe"; - let output: string[] = [], - v: number, - n = 0, - difference = 0; - if (uint8.length % 4 !== 0) { - const tmp = uint8; - difference = 4 - (tmp.length % 4); - uint8 = new Uint8Array(tmp.length + difference); - uint8.set(tmp); - } - const view = new DataView(uint8.buffer); - for (let i = 0, len = uint8.length; i < len; i += 4) { - v = view.getUint32(i); - // Adobe and btoa standards compress 4 zeroes to single "z" character - if ( - (standard === "Adobe" || standard === "btoa") && - v === 0 && - i < len - difference - 3 - ) { - output[n++] = "z"; - continue; - } - // btoa compresses 4 spaces - that is, bytes equal to 32 - into single "y" character - if (standard === "btoa" && v === 538976288) { - output[n++] = "y"; - continue; - } - for (let j = 4; j >= 0; j--) { - output[n + j] = String.fromCharCode((v % 85) + 33); - v = Math.trunc(v / 85); - } - n += 5; - } - switch (standard) { - case "Adobe": - if (options?.delimiter) { - return `<~${output.slice(0, output.length - difference).join("")}~>`; - } - break; - case "btoa": - if (options?.delimiter) { - return `xbtoa Begin\n${ - output - .slice(0, output.length - difference) - .join("") - }\nxbtoa End`; - } - break; - case "RFC 1924": - output = output.map((val) => rfc1924[val.charCodeAt(0) - 33]); - break; - case "Z85": - output = output.map((val) => Z85[val.charCodeAt(0) - 33]); - break; - } - return output.slice(0, output.length - difference).join(""); -} -/** - * Decodes a given ascii85 encoded string. - * @param ascii85 input to decode - * @param [options] decoding options - * @param [options.standard=Adobe] encoding standard used in the input string (Adobe, btoa, RFC 1924 or Z85) - */ -export function decode(ascii85: string, options?: Ascii85Options): Uint8Array { - const encoding = options?.standard ?? "Adobe"; - // translate all encodings to most basic adobe/btoa one and decompress some special characters ("z" and "y") - switch (encoding) { - case "Adobe": - ascii85 = ascii85.replaceAll(/(<~|~>)/g, "").replaceAll("z", "!!!!!"); - break; - case "btoa": - ascii85 = ascii85 - .replaceAll(/(xbtoa Begin|xbtoa End|\n)/g, "") - .replaceAll("z", "!!!!!") - .replaceAll("y", "+<VdL"); - break; - case "RFC 1924": - ascii85 = ascii85.replaceAll( - /./g, - (match) => String.fromCharCode(rfc1924.indexOf(match) + 33), - ); - break; - case "Z85": - ascii85 = ascii85.replaceAll( - /./g, - (match) => String.fromCharCode(Z85.indexOf(match) + 33), - ); - break; - } - //remove all invalid characters - ascii85 = ascii85.replaceAll(/[^!-u]/g, ""); - const len = ascii85.length, - output = new Uint8Array(len + 4 - (len % 4)); - const view = new DataView(output.buffer); - let v = 0, - n = 0, - max = 0; - for (let i = 0; i < len;) { - for (max += 5; i < max; i++) { - v = v * 85 + (i < len ? ascii85.charCodeAt(i) : 117) - 33; - } - view.setUint32(n, v); - v = 0; - n += 4; - } - return output.slice(0, Math.trunc(len * 0.8)); -} diff --git a/std/encoding/ascii85_test.ts b/std/encoding/ascii85_test.ts deleted file mode 100644 index 8bf486b8a..000000000 --- a/std/encoding/ascii85_test.ts +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assertEquals } from "../testing/asserts.ts"; -import { Ascii85Standard, decode, encode } from "./ascii85.ts"; -type TestCases = Partial<{ [index in Ascii85Standard]: string[][] }>; -const utf8encoder = new TextEncoder(); -const testCasesNoDelimiter: TestCases = { - Adobe: [ - ["test", "FCfN8"], - ["ascii85", "@<5pmBfIs"], - ["Hello world!", "87cURD]j7BEbo80"], - //wikipedia example - [ - "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.", - "9jqo^BlbD-BleB1DJ+*+F(f,q/0JhKF<GL>Cj@.4Gp$d7F!,L7@<6@)/0JDEF<G%<+EV:2F!,O<DJ+*.@<*K0@<6L(Df-\\0Ec5e;DffZ(EZee.Bl.9pF\"AGXBPCsi+DGm>@3BB/F*&OCAfu2/AKYi(DIb:@FD,*)+C]U=@3BN#EcYf8ATD3s@q?d$AftVqCh[NqF<G:8+EV:.+Cf>-FD5W8ARlolDIal(DId<j@<?3r@:F%a+D58'ATD4$Bl@l3De:,-DJs`8ARoFb/0JMK@qB4^F!,R<AKZ&-DfTqBG%G>uD.RTpAKYo'+CT/5+Cei#DII?(E,9)oF*2M7/c", - ], - ["", ""], - ["\0", "!!"], - ["\0\0", "!!!"], - ["\0\0\0", "!!!!"], - //special Adobe and btoa test cases - 4 bytes equal to 0 should become a "z" - ["\0\0\0\0", "z"], - ["\0\0\0\0\0", "z!!"], - [" ", "+<VdL"], - ], - btoa: [ - ["test", "FCfN8"], - ["ascii85", "@<5pmBfIs"], - ["Hello world!", "87cURD]j7BEbo80"], - //wikipedia example - [ - "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.", - "9jqo^BlbD-BleB1DJ+*+F(f,q/0JhKF<GL>Cj@.4Gp$d7F!,L7@<6@)/0JDEF<G%<+EV:2F!,O<DJ+*.@<*K0@<6L(Df-\\0Ec5e;DffZ(EZee.Bl.9pF\"AGXBPCsi+DGm>@3BB/F*&OCAfu2/AKYi(DIb:@FD,*)+C]U=@3BN#EcYf8ATD3s@q?d$AftVqCh[NqF<G:8+EV:.+Cf>-FD5W8ARlolDIal(DId<j@<?3r@:F%a+D58'ATD4$Bl@l3De:,-DJs`8ARoFb/0JMK@qB4^F!,R<AKZ&-DfTqBG%G>uD.RTpAKYo'+CT/5+Cei#DII?(E,9)oF*2M7/c", - ], - ["", ""], - ["\0", "!!"], - ["\0\0", "!!!"], - ["\0\0\0", "!!!!"], - //special Adobe and btoa test cases - 4 bytes equal to 0 should become a "z" - ["\0\0\0\0", "z"], - ["\0\0\0\0\0", "z!!"], - //special btoa test case - 4 spaces should become "y" - [" ", "y"], - ], - "RFC 1924": [ - ["test", "bY*jN"], - ["ascii85", "VRK_?X*e|"], - ["Hello world!", "NM&qnZy<MXa%^NF"], - //wikipedia example - [ - "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.", - "O<`^zX>%ZCX>)XGZfA9Ab7*B`EFf-gbRchTY<VDJc_3(Mb0BhMVRLV8EFfZabRc4RAarPHb0BkRZfA9DVR9gFVRLh7Z*CxFa&K)QZ**v7av))DX>DO_b1WctXlY|;AZc?TVIXXEb95kYW*~HEWgu;7Ze%PVbZB98AYyqSVIXj2a&u*NWpZI|V`U(3W*}r`Y-wj`bRcPNAarPDAY*TCbZKsNWn>^>Ze$>7Ze(R<VRUI{VPb4$AZKN6WpZJ3X>V>IZ)PBCZf|#NWn^b%EFfigV`XJzb0BnRWgv5CZ*p`Xc4cT~ZDnp_Wgu^6AYpEKAY);2ZeeU7aBO8^b9HiME&", - ], - ["", ""], - ["\0", "00"], - ["\0\0", "000"], - ["\0\0\0", "0000"], - ["\0\0\0\0", "00000"], - ["\0\0\0\0\0", "0000000"], - [" ", "ARr(h"], - ], - Z85: [ - ["test", "By/Jn"], - ["ascii85", "vrk{)x/E%"], - ["Hello world!", "nm=QNzY<mxA+]nf"], - //wikipedia example - [ - "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.", - "o<}]Zx(+zcx(!xgzFa9aB7/b}efF?GBrCHty<vdjC{3^mB0bHmvrlv8efFzABrC4raARphB0bKrzFa9dvr9GfvrlH7z/cXfA=k!qz//V7AV!!dx(do{B1wCTxLy%&azC)tvixxeB95Kyw/#hewGU&7zE+pvBzb98ayYQsvixJ2A=U/nwPzi%v}u^3w/$R}y?WJ}BrCpnaARpday/tcBzkSnwN(](zE:(7zE^r<vrui@vpB4:azkn6wPzj3x(v(iz!pbczF%-nwN]B+efFIGv}xjZB0bNrwGV5cz/P}xC4Ct#zdNP{wGU]6ayPekay!&2zEEu7Abo8]B9hIme=", - ], - ["", ""], - ["\0", "00"], - ["\0\0", "000"], - ["\0\0\0", "0000"], - ["\0\0\0\0", "00000"], - ["\0\0\0\0\0", "0000000"], - [" ", "arR^H"], - ], -}; -const testCasesDelimiter: TestCases = { - Adobe: [ - ["test", "<~FCfN8~>"], - ["ascii85", "<~@<5pmBfIs~>"], - ["Hello world!", "<~87cURD]j7BEbo80~>"], - //wikipedia example - [ - "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.", - "<~9jqo^BlbD-BleB1DJ+*+F(f,q/0JhKF<GL>Cj@.4Gp$d7F!,L7@<6@)/0JDEF<G%<+EV:2F!,O<DJ+*.@<*K0@<6L(Df-\\0Ec5e;DffZ(EZee.Bl.9pF\"AGXBPCsi+DGm>@3BB/F*&OCAfu2/AKYi(DIb:@FD,*)+C]U=@3BN#EcYf8ATD3s@q?d$AftVqCh[NqF<G:8+EV:.+Cf>-FD5W8ARlolDIal(DId<j@<?3r@:F%a+D58'ATD4$Bl@l3De:,-DJs`8ARoFb/0JMK@qB4^F!,R<AKZ&-DfTqBG%G>uD.RTpAKYo'+CT/5+Cei#DII?(E,9)oF*2M7/c~>", - ], - ["", "<~~>"], - ["\0", "<~!!~>"], - ["\0\0", "<~!!!~>"], - ["\0\0\0", "<~!!!!~>"], - //special Adobe and btoa test cases - 4 bytes equal to 0 should become a "z" - ["\0\0\0\0", "<~z~>"], - ["\0\0\0\0\0", "<~z!!~>"], - [" ", "<~+<VdL~>"], - ], - btoa: [ - ["test", "xbtoa Begin\nFCfN8\nxbtoa End"], - ["ascii85", "xbtoa Begin\n@<5pmBfIs\nxbtoa End"], - ["Hello world!", "xbtoa Begin\n87cURD]j7BEbo80\nxbtoa End"], - //wikipedia example - [ - "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.", - "xbtoa Begin\n9jqo^BlbD-BleB1DJ+*+F(f,q/0JhKF<GL>Cj@.4Gp$d7F!,L7@<6@)/0JDEF<G%<+EV:2F!,O<DJ+*.@<*K0@<6L(Df-\\0Ec5e;DffZ(EZee.Bl.9pF\"AGXBPCsi+DGm>@3BB/F*&OCAfu2/AKYi(DIb:@FD,*)+C]U=@3BN#EcYf8ATD3s@q?d$AftVqCh[NqF<G:8+EV:.+Cf>-FD5W8ARlolDIal(DId<j@<?3r@:F%a+D58'ATD4$Bl@l3De:,-DJs`8ARoFb/0JMK@qB4^F!,R<AKZ&-DfTqBG%G>uD.RTpAKYo'+CT/5+Cei#DII?(E,9)oF*2M7/c\nxbtoa End", - ], - ["", "xbtoa Begin\n\nxbtoa End"], - ["\0", "xbtoa Begin\n!!\nxbtoa End"], - ["\0\0", "xbtoa Begin\n!!!\nxbtoa End"], - ["\0\0\0", "xbtoa Begin\n!!!!\nxbtoa End"], - //special Adobe and btoa test cases - 4 bytes equal to 0 should become a "z" - ["\0\0\0\0", "xbtoa Begin\nz\nxbtoa End"], - ["\0\0\0\0\0", "xbtoa Begin\nz!!\nxbtoa End"], - //special btoa test case - 4 spaces should become "y" - [" ", "xbtoa Begin\ny\nxbtoa End"], - ], -}; - -for (const [standard, tests] of Object.entries(testCasesNoDelimiter)) { - if (tests === undefined) continue; - Deno.test({ - name: `[encoding/ascii85] encode ${standard}`, - fn(): void { - for (const [bin, b85] of tests) { - assertEquals( - encode(utf8encoder.encode(bin), { - standard: standard as Ascii85Standard, - }), - b85, - ); - } - }, - }); - - Deno.test({ - name: `[encoding/ascii85] decode ${standard}`, - fn(): void { - for (const [bin, b85] of tests) { - assertEquals( - decode(b85, { standard: standard as Ascii85Standard }), - utf8encoder.encode(bin), - ); - } - }, - }); -} -for (const [standard, tests] of Object.entries(testCasesDelimiter)) { - if (tests === undefined) continue; - Deno.test({ - name: `[encoding/ascii85] encode ${standard} with delimiter`, - fn(): void { - for (const [bin, b85] of tests) { - assertEquals( - encode(utf8encoder.encode(bin), { - standard: standard as Ascii85Standard, - delimiter: true, - }), - b85, - ); - } - }, - }); - - Deno.test({ - name: `[encoding/ascii85] decode ${standard} with delimiter`, - fn(): void { - for (const [bin, b85] of tests) { - assertEquals( - decode(b85, { - standard: standard as Ascii85Standard, - delimiter: true, - }), - utf8encoder.encode(bin), - ); - } - }, - }); -} diff --git a/std/encoding/base32.ts b/std/encoding/base32.ts deleted file mode 100644 index 7d0ec81f3..000000000 --- a/std/encoding/base32.ts +++ /dev/null @@ -1,207 +0,0 @@ -// Modified from https://github.com/beatgammit/base64-js -// Copyright (c) 2014 Jameson Little. MIT License. - -const lookup: string[] = []; -const revLookup: number[] = []; - -// RFC4648 base32 -const code = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; -for (let i = 0, len = code.length; i < len; ++i) { - lookup[i] = code[i]; - revLookup[code.charCodeAt(i)] = i; -} - -const placeHolderPadLookup = [0, 1, , 2, 3, , 4]; -function _getPadLen(placeHoldersLen: number): number { - const maybeLen = placeHolderPadLookup[placeHoldersLen]; - if (typeof maybeLen !== "number") { - throw new Error("Invalid pad length"); - } - return maybeLen; -} - -function getLens(b32: string): [number, number] { - const len = b32.length; - - if (len % 8 > 0) { - throw new Error("Invalid string. Length must be a multiple of 8"); - } - - let validLen = b32.indexOf("="); - if (validLen === -1) validLen = len; - - const placeHoldersLen = validLen === len ? 0 : 8 - (validLen % 8); - - return [validLen, placeHoldersLen]; -} - -/** - * Returns number of bytes encoded in the given RFC4648 base32 string input. - * @param b32 - */ -export function byteLength(b32: string): number { - const [validLen, placeHoldersLen] = getLens(b32); - return _byteLength(validLen, placeHoldersLen); -} - -function _byteLength(validLen: number, placeHoldersLen: number): number { - return ((validLen + placeHoldersLen) * 5) / 8 - _getPadLen(placeHoldersLen); -} - -/** - * Decodes a given RFC4648 base32 encoded string. - * @param b32 - */ -export function decode(b32: string): Uint8Array { - let tmp: number; - const [validLen, placeHoldersLen] = getLens(b32); - - const arr = new Uint8Array(_byteLength(validLen, placeHoldersLen)); - - let curByte = 0; - - // if there are placeholders, only get up to the last complete 8 chars - const len = placeHoldersLen > 0 ? validLen - 8 : validLen; - - let i: number; - for (i = 0; i < len; i += 8) { - tmp = (revLookup[b32.charCodeAt(i)] << 20) | - (revLookup[b32.charCodeAt(i + 1)] << 15) | - (revLookup[b32.charCodeAt(i + 2)] << 10) | - (revLookup[b32.charCodeAt(i + 3)] << 5) | - revLookup[b32.charCodeAt(i + 4)]; - arr[curByte++] = (tmp >> 17) & 0xff; - arr[curByte++] = (tmp >> 9) & 0xff; - arr[curByte++] = (tmp >> 1) & 0xff; - - tmp = ((tmp & 1) << 15) | - (revLookup[b32.charCodeAt(i + 5)] << 10) | - (revLookup[b32.charCodeAt(i + 6)] << 5) | - revLookup[b32.charCodeAt(i + 7)]; - arr[curByte++] = (tmp >> 8) & 0xff; - arr[curByte++] = tmp & 0xff; - } - - if (placeHoldersLen === 1) { - tmp = (revLookup[b32.charCodeAt(i)] << 20) | - (revLookup[b32.charCodeAt(i + 1)] << 15) | - (revLookup[b32.charCodeAt(i + 2)] << 10) | - (revLookup[b32.charCodeAt(i + 3)] << 5) | - revLookup[b32.charCodeAt(i + 4)]; - arr[curByte++] = (tmp >> 17) & 0xff; - arr[curByte++] = (tmp >> 9) & 0xff; - arr[curByte++] = (tmp >> 1) & 0xff; - tmp = ((tmp & 1) << 7) | - (revLookup[b32.charCodeAt(i + 5)] << 2) | - (revLookup[b32.charCodeAt(i + 6)] >> 3); - arr[curByte++] = tmp & 0xff; - } else if (placeHoldersLen === 3) { - tmp = (revLookup[b32.charCodeAt(i)] << 19) | - (revLookup[b32.charCodeAt(i + 1)] << 14) | - (revLookup[b32.charCodeAt(i + 2)] << 9) | - (revLookup[b32.charCodeAt(i + 3)] << 4) | - (revLookup[b32.charCodeAt(i + 4)] >> 1); - arr[curByte++] = (tmp >> 16) & 0xff; - arr[curByte++] = (tmp >> 8) & 0xff; - arr[curByte++] = tmp & 0xff; - } else if (placeHoldersLen === 4) { - tmp = (revLookup[b32.charCodeAt(i)] << 11) | - (revLookup[b32.charCodeAt(i + 1)] << 6) | - (revLookup[b32.charCodeAt(i + 2)] << 1) | - (revLookup[b32.charCodeAt(i + 3)] >> 4); - arr[curByte++] = (tmp >> 8) & 0xff; - arr[curByte++] = tmp & 0xff; - } else if (placeHoldersLen === 6) { - tmp = (revLookup[b32.charCodeAt(i)] << 3) | - (revLookup[b32.charCodeAt(i + 1)] >> 2); - arr[curByte++] = tmp & 0xff; - } - - return arr; -} - -function encodeChunk(uint8: Uint8Array, start: number, end: number): string { - let tmp: number; - const output = []; - for (let i = start; i < end; i += 5) { - tmp = ((uint8[i] << 16) & 0xff0000) | - ((uint8[i + 1] << 8) & 0xff00) | - (uint8[i + 2] & 0xff); - output.push(lookup[(tmp >> 19) & 0x1f]); - output.push(lookup[(tmp >> 14) & 0x1f]); - output.push(lookup[(tmp >> 9) & 0x1f]); - output.push(lookup[(tmp >> 4) & 0x1f]); - tmp = ((tmp & 0xf) << 16) | - ((uint8[i + 3] << 8) & 0xff00) | - (uint8[i + 4] & 0xff); - output.push(lookup[(tmp >> 15) & 0x1f]); - output.push(lookup[(tmp >> 10) & 0x1f]); - output.push(lookup[(tmp >> 5) & 0x1f]); - output.push(lookup[tmp & 0x1f]); - } - return output.join(""); -} - -/** - * Encodes a given Uint8Array into RFC4648 base32 representation - * @param uint8 - */ -export function encode(uint8: Uint8Array): string { - let tmp: number; - const len = uint8.length; - const extraBytes = len % 5; - const parts = []; - const maxChunkLength = 16385; // must be multiple of 5 - const len2 = len - extraBytes; - - // go through the array every 5 bytes, we'll deal with trailing stuff later - for (let i = 0; i < len2; i += maxChunkLength) { - parts.push( - encodeChunk( - uint8, - i, - i + maxChunkLength > len2 ? len2 : i + maxChunkLength, - ), - ); - } - - // pad the end with zeros, but make sure to not forget the extra bytes - if (extraBytes === 4) { - tmp = ((uint8[len2] & 0xff) << 16) | - ((uint8[len2 + 1] & 0xff) << 8) | - (uint8[len2 + 2] & 0xff); - parts.push(lookup[(tmp >> 19) & 0x1f]); - parts.push(lookup[(tmp >> 14) & 0x1f]); - parts.push(lookup[(tmp >> 9) & 0x1f]); - parts.push(lookup[(tmp >> 4) & 0x1f]); - tmp = ((tmp & 0xf) << 11) | (uint8[len2 + 3] << 3); - parts.push(lookup[(tmp >> 10) & 0x1f]); - parts.push(lookup[(tmp >> 5) & 0x1f]); - parts.push(lookup[tmp & 0x1f]); - parts.push("="); - } else if (extraBytes === 3) { - tmp = ((uint8[len2] & 0xff) << 17) | - ((uint8[len2 + 1] & 0xff) << 9) | - ((uint8[len2 + 2] & 0xff) << 1); - parts.push(lookup[(tmp >> 20) & 0x1f]); - parts.push(lookup[(tmp >> 15) & 0x1f]); - parts.push(lookup[(tmp >> 10) & 0x1f]); - parts.push(lookup[(tmp >> 5) & 0x1f]); - parts.push(lookup[tmp & 0x1f]); - parts.push("==="); - } else if (extraBytes === 2) { - tmp = ((uint8[len2] & 0xff) << 12) | ((uint8[len2 + 1] & 0xff) << 4); - parts.push(lookup[(tmp >> 15) & 0x1f]); - parts.push(lookup[(tmp >> 10) & 0x1f]); - parts.push(lookup[(tmp >> 5) & 0x1f]); - parts.push(lookup[tmp & 0x1f]); - parts.push("===="); - } else if (extraBytes === 1) { - tmp = (uint8[len2] & 0xff) << 2; - parts.push(lookup[(tmp >> 5) & 0x1f]); - parts.push(lookup[tmp & 0x1f]); - parts.push("======"); - } - - return parts.join(""); -} diff --git a/std/encoding/base32_test.ts b/std/encoding/base32_test.ts deleted file mode 100644 index 1c497182f..000000000 --- a/std/encoding/base32_test.ts +++ /dev/null @@ -1,135 +0,0 @@ -// Test cases copied from https://github.com/LinusU/base32-encode/blob/master/test.js -// Copyright (c) 2016-2017 Linus Unnebäck. MIT license. -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assert, assertEquals } from "../testing/asserts.ts"; -import { decode, encode } from "./base32.ts"; - -// Lifted from https://stackoverflow.com/questions/38987784 -const fromHexString = (hexString: string): Uint8Array => - new Uint8Array(hexString.match(/.{1,2}/g)!.map((byte) => parseInt(byte, 16))); -const toHexString = (bytes: Uint8Array): string => - bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), ""); - -const testCases = [ - ["73", "OM======"], - ["f80c", "7AGA===="], - ["6450", "MRIA===="], - ["cc91d0", "ZSI5A==="], - ["6c60c0", "NRQMA==="], - ["4f6a23", "J5VCG==="], - ["88b44f18", "RC2E6GA="], - ["90bad04714", "SC5NARYU"], - ["e9ef1def8086", "5HXR334AQY======"], - ["83fe3f9c1e9302", "QP7D7HA6SMBA===="], - ["15aa1f7cafc17cb8", "CWVB67FPYF6LQ==="], - ["da51d4fed48b4c32dc", "3JI5J7WURNGDFXA="], - ["c4be14228512d7299831", "YS7BIIUFCLLSTGBR"], - ["2f273c5b5ef04724fab944", "F4TTYW266BDSJ6VZIQ======"], - ["969da1b80ec2442d2bdd4bdb", "S2O2DOAOYJCC2K65JPNQ===="], - ["31f5adb50792f549d3714f3f99", "GH223NIHSL2UTU3RJ47ZS==="], - ["6a654f7a072c29951930700c0a61", "NJSU66QHFQUZKGJQOAGAUYI="], - ["0fe29d6825ad999e87d9b7cac3589d", "B7RJ22BFVWMZ5B6ZW7FMGWE5"], - ["0f960ab44e165973a5172ccd294b3412", "B6LAVNCOCZMXHJIXFTGSSSZUCI======"], - ["325b9fd847a41fb0d485c207a1a5b02dcf", "GJNZ7WCHUQP3BVEFYID2DJNQFXHQ===="], - ["ddf80ebe21bf1b1e12a64c5cc6a74b5d92dd", "3X4A5PRBX4NR4EVGJROMNJ2LLWJN2==="], - [ - "c0cae52c6f641ce04a7ee5b9a8fa8ded121bca", - "YDFOKLDPMQOOAST64W42R6UN5UJBXSQ=", - ], - [ - "872840a355c8c70586f462c9e669ee760cb3537e", - "Q4UEBI2VZDDQLBXUMLE6M2POOYGLGU36", - ], - [ - "5773fe22662818a120c5688824c935fe018208a496", - "K5Z74ITGFAMKCIGFNCECJSJV7YAYECFESY======", - ], - [ - "416e23abc524d1b85736e2bea6cfecd5192789034a28", - "IFXCHK6FETI3QVZW4K7KNT7M2UMSPCIDJIUA====", - ], - [ - "83d2386ebdd7e8e818ec00e3ccd882aa933b905b7e2e44", - "QPJDQ3V527UOQGHMADR4ZWECVKJTXEC3PYXEI===", - ], - [ - "a2fa8b881f3b8024f52745763c4ae08ea12bdf8bef1a72f8", - "UL5IXCA7HOACJ5JHIV3DYSXAR2QSXX4L54NHF6A=", - ], - [ - "b074ae8b9efde0f17f37bccadde006d039997b59c8efb05add", - "WB2K5C467XQPC7ZXXTFN3YAG2A4ZS62ZZDX3AWW5", - ], - [ - "764fef941aee7e416dc204ae5ab9c5b9ce644567798e6849aea9", - "OZH67FA25Z7EC3OCASXFVOOFXHHGIRLHPGHGQSNOVE======", - ], - [ - "4995d9811f37f59797d7c3b9b9e5325aa78277415f70f4accf588c", - "JGK5TAI7G72ZPF6XYO43TZJSLKTYE52BL5YPJLGPLCGA====", - ], - [ - "24f0812ca8eed58374c11a7008f0b262698b72fd2792709208eaacb2", - "ETYICLFI53KYG5GBDJYAR4FSMJUYW4X5E6JHBEQI5KWLE===", - ], - [ - "d70692543810d4bf50d81cf44a55801a557a388a341367c7ea077ca306", - "24DJEVBYCDKL6UGYDT2EUVMADJKXUOEKGQJWPR7KA56KGBQ=", - ], - [ - "6e08a89ca36b677ff8fe99e68a1241c8d8cef2570a5f60b6417d2538b30c", - "NYEKRHFDNNTX76H6THTIUESBZDMM54SXBJPWBNSBPUSTRMYM", - ], - [ - "f2fc2319bd29457ccd01e8e194ee9bd7e97298b6610df4ab0f3d5baa0b2d7ccf69829edb74edef", - "6L6CGGN5FFCXZTIB5DQZJ3U327UXFGFWMEG7JKYPHVN2UCZNPTHWTAU63N2O33Y=", - ], -]; - -Deno.test({ - name: "[encoding.base32] encode", - fn(): void { - for (const [bin, b32] of testCases) { - assertEquals(encode(fromHexString(bin)), b32); - } - }, -}); - -Deno.test({ - name: "[encoding.base32] decode", - fn(): void { - for (const [bin, b32] of testCases) { - assertEquals(toHexString(decode(b32)), bin); - } - }, -}); - -Deno.test({ - name: "[encoding.base32] decode bad length", - fn(): void { - let errorCaught = false; - try { - decode("OOOO=="); - } catch (e) { - assert( - e.message.includes("Invalid string. Length must be a multiple of 8"), - ); - errorCaught = true; - } - assert(errorCaught); - }, -}); - -Deno.test({ - name: "[encoding.base32] decode bad padding", - fn(): void { - let errorCaught = false; - try { - decode("OOOOOO=="); - } catch (e) { - assert(e.message.includes("Invalid pad length")); - errorCaught = true; - } - assert(errorCaught); - }, -}); diff --git a/std/encoding/base64.ts b/std/encoding/base64.ts deleted file mode 100644 index c98030b7f..000000000 --- a/std/encoding/base64.ts +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -// deno-fmt-ignore -const base64abc = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", - "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", - "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", - "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", - "5", "6", "7", "8", "9", "+", "/"]; - -/** - * CREDIT: https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727 - * Encodes a given Uint8Array, ArrayBuffer or string into RFC4648 base64 representation - * @param data - */ -export function encode(data: ArrayBuffer | string): string { - const uint8 = - typeof data === "string" - ? new TextEncoder().encode(data) - : data instanceof Uint8Array - ? data - : new Uint8Array(data); - let result = "", - i; - const l = uint8.length; - for (i = 2; i < l; i += 3) { - result += base64abc[uint8[i - 2] >> 2]; - result += base64abc[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)]; - result += base64abc[((uint8[i - 1] & 0x0f) << 2) | (uint8[i] >> 6)]; - result += base64abc[uint8[i] & 0x3f]; - } - if (i === l + 1) { - // 1 octet yet to write - result += base64abc[uint8[i - 2] >> 2]; - result += base64abc[(uint8[i - 2] & 0x03) << 4]; - result += "=="; - } - if (i === l) { - // 2 octets yet to write - result += base64abc[uint8[i - 2] >> 2]; - result += base64abc[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)]; - result += base64abc[(uint8[i - 1] & 0x0f) << 2]; - result += "="; - } - return result; -} - -/** - * Decodes a given RFC4648 base64 encoded string - * @param b64 - */ -export function decode(b64: string): Uint8Array { - const binString = atob(b64); - const size = binString.length; - const bytes = new Uint8Array(size); - for (let i = 0; i < size; i++) { - bytes[i] = binString.charCodeAt(i); - } - return bytes; -} diff --git a/std/encoding/base64_test.ts b/std/encoding/base64_test.ts deleted file mode 100644 index 829deb688..000000000 --- a/std/encoding/base64_test.ts +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -import { assertEquals } from "../testing/asserts.ts"; -import { decode, encode } from "./base64.ts"; - -const testsetString = [ - ["", ""], - ["ß", "w58="], - ["f", "Zg=="], - ["fo", "Zm8="], - ["foo", "Zm9v"], - ["foob", "Zm9vYg=="], - ["fooba", "Zm9vYmE="], - ["foobar", "Zm9vYmFy"], -]; - -const testsetBinary = testsetString.map(([str, b64]) => [ - new TextEncoder().encode(str), - b64, -]) as Array<[Uint8Array, string]>; - -Deno.test("[encoding/base64] testBase64EncodeString", () => { - for (const [input, output] of testsetString) { - assertEquals(encode(input), output); - } -}); - -Deno.test("[encoding/base64] testBase64EncodeBinary", () => { - for (const [input, output] of testsetBinary) { - assertEquals(encode(input), output); - } -}); - -Deno.test("[encoding/base64] testBase64EncodeBinaryBuffer", () => { - for (const [input, output] of testsetBinary) { - assertEquals(encode(input.buffer), output); - } -}); - -Deno.test("[encoding/base64] testBase64DecodeBinary", () => { - for (const [input, output] of testsetBinary) { - const outputBinary = decode(output); - assertEquals(outputBinary, input); - } -}); diff --git a/std/encoding/base64url.ts b/std/encoding/base64url.ts deleted file mode 100644 index 45de1bd6d..000000000 --- a/std/encoding/base64url.ts +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -import * as base64 from "./base64.ts"; - -/* - * Some variants allow or require omitting the padding '=' signs: - * https://en.wikipedia.org/wiki/Base64#URL_applications - * @param base64url - */ -export function addPaddingToBase64url(base64url: string): string { - if (base64url.length % 4 === 2) return base64url + "=="; - if (base64url.length % 4 === 3) return base64url + "="; - if (base64url.length % 4 === 1) { - throw new TypeError("Illegal base64url string!"); - } - return base64url; -} - -function convertBase64urlToBase64(b64url: string): string { - return addPaddingToBase64url(b64url).replace(/\-/g, "+").replace(/_/g, "/"); -} - -function convertBase64ToBase64url(b64: string): string { - return b64.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_"); -} - -/** - * Encodes a given Uint8Array into a base64url representation - * @param uint8 - */ -export function encode(uint8: Uint8Array): string { - return convertBase64ToBase64url(base64.encode(uint8)); -} - -/** - * Converts given base64url encoded data back to original - * @param b64url - */ -export function decode(b64url: string): Uint8Array { - return base64.decode(convertBase64urlToBase64(b64url)); -} diff --git a/std/encoding/base64url_test.ts b/std/encoding/base64url_test.ts deleted file mode 100644 index 3a41c5f64..000000000 --- a/std/encoding/base64url_test.ts +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -import { assertEquals } from "../testing/asserts.ts"; -import { decode, encode } from "./base64url.ts"; - -const testsetString = [ - ["", ""], - ["ß", "w58"], - ["f", "Zg"], - ["fo", "Zm8"], - ["foo", "Zm9v"], - ["foob", "Zm9vYg"], - ["fooba", "Zm9vYmE"], - ["foobar", "Zm9vYmFy"], - [">?>d?ß", "Pj8-ZD_Dnw"], -]; - -const testsetBinary = testsetString.map(([str, b64]) => [ - new TextEncoder().encode(str), - b64, -]) as Array<[Uint8Array, string]>; - -Deno.test("[encoding/base64url] testBase64urlEncodeBinary", () => { - for (const [input, output] of testsetBinary) { - assertEquals(encode(input), output); - } -}); - -Deno.test("[decoding/base64url] testBase64urlDecodeBinary", () => { - for (const [input, output] of testsetBinary) { - assertEquals(decode(output), input); - } -}); diff --git a/std/encoding/binary.ts b/std/encoding/binary.ts deleted file mode 100644 index f62b3b7a4..000000000 --- a/std/encoding/binary.ts +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -type RawBaseType = "int8" | "int16" | "int32" | "uint8" | "uint16" | "uint32"; -type RawNumberType = RawBaseType | "float32" | "float64"; -type RawBigType = RawBaseType | "int64" | "uint64"; -export type DataType = RawNumberType | RawBigType; - -/** How encoded binary data is ordered. */ -export type Endianness = "little" | "big"; - -/** Options for working with the `number` type. */ -export interface VarnumOptions { - /** The binary format used. */ - dataType?: RawNumberType; - /** The binary encoding order used. */ - endian?: Endianness; -} - -/** Options for working with the `bigint` type. */ -export interface VarbigOptions { - /** The binary format used. */ - dataType?: RawBigType; - /** The binary encoding order used. */ - endian?: Endianness; -} - -const rawTypeSizes: Record<DataType, number> = { - int8: 1, - uint8: 1, - int16: 2, - uint16: 2, - int32: 4, - uint32: 4, - int64: 8, - uint64: 8, - float32: 4, - float64: 8, -} as const; - -/** Number of bytes required to store `dataType`. */ -export function sizeof(dataType: DataType): number { - return rawTypeSizes[dataType]; -} - -/** Reads `n` bytes from `r`. - * - * Resolves it in a `Uint8Array`, or throws `Deno.errors.UnexpectedEof` if `n` bytes cannot be read. */ -export async function getNBytes( - r: Deno.Reader, - n: number, -): Promise<Uint8Array> { - const scratch = new Uint8Array(n); - const nRead = await r.read(scratch); - if (nRead === null || nRead < n) throw new Deno.errors.UnexpectedEof(); - return scratch; -} - -/** Decodes a number from `b`. If `o.bytes` is shorter than `sizeof(o.dataType)`, returns `null`. - * - * `o.dataType` defaults to `"int32"`. */ -export function varnum(b: Uint8Array, o: VarnumOptions = {}): number | null { - o.dataType = o.dataType ?? "int32"; - const littleEndian = (o.endian ?? "big") === "little" ? true : false; - if (b.length < sizeof(o.dataType)) return null; - const view = new DataView(b.buffer); - switch (o.dataType) { - case "int8": - return view.getInt8(0); - case "uint8": - return view.getUint8(0); - case "int16": - return view.getInt16(0, littleEndian); - case "uint16": - return view.getUint16(0, littleEndian); - case "int32": - return view.getInt32(0, littleEndian); - case "uint32": - return view.getUint32(0, littleEndian); - case "float32": - return view.getFloat32(0, littleEndian); - case "float64": - return view.getFloat64(0, littleEndian); - } -} - -/** Decodes a bigint from `b`. If `o.bytes` is shorter than `sizeof(o.dataType)`, returns `null`. - * - * `o.dataType` defaults to `"int64"`. */ -export function varbig(b: Uint8Array, o: VarbigOptions = {}): bigint | null { - o.dataType = o.dataType ?? "int64"; - const littleEndian = (o.endian ?? "big") === "little" ? true : false; - if (b.length < sizeof(o.dataType)) return null; - const view = new DataView(b.buffer); - switch (o.dataType) { - case "int8": - return BigInt(view.getInt8(0)); - case "uint8": - return BigInt(view.getUint8(0)); - case "int16": - return BigInt(view.getInt16(0, littleEndian)); - case "uint16": - return BigInt(view.getUint16(0, littleEndian)); - case "int32": - return BigInt(view.getInt32(0, littleEndian)); - case "uint32": - return BigInt(view.getUint32(0, littleEndian)); - case "int64": - return view.getBigInt64(0, littleEndian); - case "uint64": - return view.getBigUint64(0, littleEndian); - } -} - -/** Encodes number `x` into `b`. Returns the number of bytes used, or `0` if `b` is shorter than `sizeof(o.dataType)`. - * - * `o.dataType` defaults to `"int32"`. */ -export function putVarnum( - b: Uint8Array, - x: number, - o: VarnumOptions = {}, -): number { - o.dataType = o.dataType ?? "int32"; - const littleEndian = (o.endian ?? "big") === "little" ? true : false; - if (b.length < sizeof(o.dataType)) return 0; - const view = new DataView(b.buffer); - switch (o.dataType) { - case "int8": - view.setInt8(0, x); - break; - case "uint8": - view.setUint8(0, x); - break; - case "int16": - view.setInt16(0, x, littleEndian); - break; - case "uint16": - view.setUint16(0, x, littleEndian); - break; - case "int32": - view.setInt32(0, x, littleEndian); - break; - case "uint32": - view.setUint32(0, x, littleEndian); - break; - case "float32": - view.setFloat32(0, x, littleEndian); - break; - case "float64": - view.setFloat64(0, x, littleEndian); - break; - } - return sizeof(o.dataType); -} - -/** Encodes bigint `x` into `b`. Returns the number of bytes used, or `0` if `b` is shorter than `sizeof(o.dataType)`. - * - * `o.dataType` defaults to `"int64"`. */ -export function putVarbig( - b: Uint8Array, - x: bigint, - o: VarbigOptions = {}, -): number { - o.dataType = o.dataType ?? "int64"; - const littleEndian = (o.endian ?? "big") === "little" ? true : false; - if (b.length < sizeof(o.dataType)) return 0; - const view = new DataView(b.buffer); - switch (o.dataType) { - case "int8": - view.setInt8(0, Number(x)); - break; - case "uint8": - view.setUint8(0, Number(x)); - break; - case "int16": - view.setInt16(0, Number(x), littleEndian); - break; - case "uint16": - view.setUint16(0, Number(x), littleEndian); - break; - case "int32": - view.setInt32(0, Number(x), littleEndian); - break; - case "uint32": - view.setUint32(0, Number(x), littleEndian); - break; - case "int64": - view.setBigInt64(0, x, littleEndian); - break; - case "uint64": - view.setBigUint64(0, x, littleEndian); - break; - } - return sizeof(o.dataType); -} - -/** Decodes a number from `r`, consuming `sizeof(o.dataType)` bytes. If less than `sizeof(o.dataType)` bytes were read, throws `Deno.errors.unexpectedEof`. - * - * `o.dataType` defaults to `"int32"`. */ -export async function readVarnum( - r: Deno.Reader, - o: VarnumOptions = {}, -): Promise<number> { - o.dataType = o.dataType ?? "int32"; - const scratch = await getNBytes(r, sizeof(o.dataType)); - return varnum(scratch, o) as number; -} - -/** Decodes a bigint from `r`, consuming `sizeof(o.dataType)` bytes. If less than `sizeof(o.dataType)` bytes were read, throws `Deno.errors.unexpectedEof`. - * - * `o.dataType` defaults to `"int64"`. */ -export async function readVarbig( - r: Deno.Reader, - o: VarbigOptions = {}, -): Promise<bigint> { - o.dataType = o.dataType ?? "int64"; - const scratch = await getNBytes(r, sizeof(o.dataType)); - return varbig(scratch, o) as bigint; -} - -/** Encodes and writes `x` to `w`. Resolves to the number of bytes written. - * - * `o.dataType` defaults to `"int32"`. */ -export function writeVarnum( - w: Deno.Writer, - x: number, - o: VarnumOptions = {}, -): Promise<number> { - o.dataType = o.dataType ?? "int32"; - const scratch = new Uint8Array(sizeof(o.dataType)); - putVarnum(scratch, x, o); - return w.write(scratch); -} - -/** Encodes and writes `x` to `w`. Resolves to the number of bytes written. - * - * `o.dataType` defaults to `"int64"`. */ -export function writeVarbig( - w: Deno.Writer, - x: bigint, - o: VarbigOptions = {}, -): Promise<number> { - o.dataType = o.dataType ?? "int64"; - const scratch = new Uint8Array(sizeof(o.dataType)); - putVarbig(scratch, x, o); - return w.write(scratch); -} - -/** Encodes `x` into a new `Uint8Array`. - * - * `o.dataType` defaults to `"int32"` */ -export function varnumBytes(x: number, o: VarnumOptions = {}): Uint8Array { - o.dataType = o.dataType ?? "int32"; - const b = new Uint8Array(sizeof(o.dataType)); - putVarnum(b, x, o); - return b; -} - -/** Encodes `x` into a new `Uint8Array`. - * - * `o.dataType` defaults to `"int64"` */ -export function varbigBytes(x: bigint, o: VarbigOptions = {}): Uint8Array { - o.dataType = o.dataType ?? "int64"; - const b = new Uint8Array(sizeof(o.dataType)); - putVarbig(b, x, o); - return b; -} diff --git a/std/encoding/binary_test.ts b/std/encoding/binary_test.ts deleted file mode 100644 index 5688b84a2..000000000 --- a/std/encoding/binary_test.ts +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -import { assertEquals, assertThrowsAsync } from "../testing/asserts.ts"; -import { - getNBytes, - putVarbig, - putVarnum, - readVarbig, - readVarnum, - sizeof, - varbig, - varbigBytes, - varnum, - varnumBytes, - writeVarbig, - writeVarnum, -} from "./binary.ts"; - -Deno.test("testGetNBytes", async function (): Promise<void> { - const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); - const buff = new Deno.Buffer(data.buffer); - const rslt = await getNBytes(buff, 8); - assertEquals(rslt, data); -}); - -Deno.test("testGetNBytesThrows", async function (): Promise<void> { - const data = new Uint8Array([1, 2, 3, 4]); - const buff = new Deno.Buffer(data.buffer); - await assertThrowsAsync(async () => { - await getNBytes(buff, 8); - }, Deno.errors.UnexpectedEof); -}); - -Deno.test("testPutVarbig", function (): void { - const buff = new Uint8Array(8); - putVarbig(buff, 0xffeeddccbbaa9988n); - assertEquals( - buff, - new Uint8Array([0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88]), - ); -}); - -Deno.test("testPutVarbigLittleEndian", function (): void { - const buff = new Uint8Array(8); - putVarbig(buff, 0x8899aabbccddeeffn, { endian: "little" }); - assertEquals( - buff, - new Uint8Array([0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88]), - ); -}); - -Deno.test("testPutVarnum", function (): void { - const buff = new Uint8Array(4); - putVarnum(buff, 0xffeeddcc); - assertEquals(buff, new Uint8Array([0xff, 0xee, 0xdd, 0xcc])); -}); - -Deno.test("testPutVarnumLittleEndian", function (): void { - const buff = new Uint8Array(4); - putVarnum(buff, 0xccddeeff, { endian: "little" }); - assertEquals(buff, new Uint8Array([0xff, 0xee, 0xdd, 0xcc])); -}); - -Deno.test("testReadVarbig", async function (): Promise<void> { - const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); - const buff = new Deno.Buffer(data.buffer); - const rslt = await readVarbig(buff); - assertEquals(rslt, 0x0102030405060708n); -}); - -Deno.test("testReadVarbigLittleEndian", async function (): Promise<void> { - const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); - const buff = new Deno.Buffer(data.buffer); - const rslt = await readVarbig(buff, { endian: "little" }); - assertEquals(rslt, 0x0807060504030201n); -}); - -Deno.test("testReadVarnum", async function (): Promise<void> { - const data = new Uint8Array([1, 2, 3, 4]); - const buff = new Deno.Buffer(data.buffer); - const rslt = await readVarnum(buff); - assertEquals(rslt, 0x01020304); -}); - -Deno.test("testReadVarnumLittleEndian", async function (): Promise<void> { - const data = new Uint8Array([1, 2, 3, 4]); - const buff = new Deno.Buffer(data.buffer); - const rslt = await readVarnum(buff, { endian: "little" }); - assertEquals(rslt, 0x04030201); -}); - -Deno.test("testSizeof", function (): void { - assertEquals(1, sizeof("int8")); - assertEquals(1, sizeof("uint8")); - assertEquals(2, sizeof("int16")); - assertEquals(2, sizeof("uint16")); - assertEquals(4, sizeof("int32")); - assertEquals(4, sizeof("uint32")); - assertEquals(8, sizeof("int64")); - assertEquals(8, sizeof("uint64")); - assertEquals(4, sizeof("float32")); - assertEquals(8, sizeof("float64")); -}); - -Deno.test("testVarbig", function (): void { - const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); - const rslt = varbig(data); - assertEquals(rslt, 0x0102030405060708n); -}); - -Deno.test("testVarbigLittleEndian", function (): void { - const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); - const rslt = varbig(data, { endian: "little" }); - assertEquals(rslt, 0x0807060504030201n); -}); - -Deno.test("testVarnum", function (): void { - const data = new Uint8Array([1, 2, 3, 4]); - const rslt = varnum(data); - assertEquals(rslt, 0x01020304); -}); -Deno.test("testVarnumLittleEndian", function (): void { - const data = new Uint8Array([1, 2, 3, 4]); - const rslt = varnum(data, { endian: "little" }); - assertEquals(rslt, 0x04030201); -}); - -Deno.test("testWriteVarbig", async function (): Promise<void> { - const data = new Uint8Array(8); - const buff = new Deno.Buffer(); - await writeVarbig(buff, 0x0102030405060708n); - await buff.read(data); - assertEquals( - data, - new Uint8Array([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]), - ); -}); - -Deno.test("testWriteVarbigLittleEndian", async function (): Promise<void> { - const data = new Uint8Array(8); - const buff = new Deno.Buffer(); - await writeVarbig(buff, 0x0807060504030201n, { endian: "little" }); - await buff.read(data); - assertEquals( - data, - new Uint8Array([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]), - ); -}); - -Deno.test("testWriteVarnum", async function (): Promise<void> { - const data = new Uint8Array(4); - const buff = new Deno.Buffer(); - await writeVarnum(buff, 0x01020304); - await buff.read(data); - assertEquals(data, new Uint8Array([0x01, 0x02, 0x03, 0x04])); -}); - -Deno.test("testWriteVarnumLittleEndian", async function (): Promise<void> { - const data = new Uint8Array(4); - const buff = new Deno.Buffer(); - await writeVarnum(buff, 0x04030201, { endian: "little" }); - await buff.read(data); - assertEquals(data, new Uint8Array([0x01, 0x02, 0x03, 0x04])); -}); - -Deno.test("testVarbigBytes", function (): void { - const rslt = varbigBytes(0x0102030405060708n); - assertEquals( - rslt, - new Uint8Array([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]), - ); -}); - -Deno.test("testVarbigBytesLittleEndian", function (): void { - const rslt = varbigBytes(0x0807060504030201n, { endian: "little" }); - assertEquals( - rslt, - new Uint8Array([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]), - ); -}); - -Deno.test("testVarnumBytes", function (): void { - const rslt = varnumBytes(0x01020304); - assertEquals(rslt, new Uint8Array([0x01, 0x02, 0x03, 0x04])); -}); - -Deno.test("testVarnumBytesLittleEndian", function (): void { - const rslt = varnumBytes(0x04030201, { endian: "little" }); - assertEquals(rslt, new Uint8Array([0x01, 0x02, 0x03, 0x04])); -}); diff --git a/std/encoding/csv.ts b/std/encoding/csv.ts deleted file mode 100644 index bda28c1d9..000000000 --- a/std/encoding/csv.ts +++ /dev/null @@ -1,462 +0,0 @@ -// Ported from Go: -// https://github.com/golang/go/blob/go1.12.5/src/encoding/csv/ -// Copyright 2011 The Go Authors. All rights reserved. BSD license. -// https://github.com/golang/go/blob/master/LICENSE -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -import { BufReader } from "../io/bufio.ts"; -import { TextProtoReader } from "../textproto/mod.ts"; -import { StringReader } from "../io/readers.ts"; -import { assert } from "../_util/assert.ts"; - -export { NEWLINE, stringify, StringifyError } from "./csv_stringify.ts"; - -export type { - Column, - ColumnDetails, - DataItem, - StringifyOptions, -} from "./csv_stringify.ts"; - -const INVALID_RUNE = ["\r", "\n", '"']; - -export const ERR_BARE_QUOTE = 'bare " in non-quoted-field'; -export const ERR_QUOTE = 'extraneous or missing " in quoted-field'; -export const ERR_INVALID_DELIM = "Invalid Delimiter"; -export const ERR_FIELD_COUNT = "wrong number of fields"; - -/** - * A ParseError is returned for parsing errors. - * Line numbers are 1-indexed and columns are 0-indexed. - */ -export class ParseError extends Error { - /** Line where the record starts*/ - startLine: number; - /** Line where the error occurred */ - line: number; - /** Column (rune index) where the error occurred */ - column: number | null; - - constructor( - start: number, - line: number, - column: number | null, - message: string, - ) { - super(); - this.startLine = start; - this.column = column; - this.line = line; - - if (message === ERR_FIELD_COUNT) { - this.message = `record on line ${line}: ${message}`; - } else if (start !== line) { - this.message = - `record on line ${start}; parse error on line ${line}, column ${column}: ${message}`; - } else { - this.message = - `parse error on line ${line}, column ${column}: ${message}`; - } - } -} - -/** - * @property separator - Character which separates values. Default: ',' - * @property comment - Character to start a comment. Default: '#' - * @property trimLeadingSpace - Flag to trim the leading space of the value. - * Default: 'false' - * @property lazyQuotes - Allow unquoted quote in a quoted field or non double - * quoted quotes in quoted field. Default: 'false' - * @property fieldsPerRecord - Enabling the check of fields for each row. - * If == 0, first row is used as referral for the number of fields. - */ -export interface ReadOptions { - separator?: string; - comment?: string; - trimLeadingSpace?: boolean; - lazyQuotes?: boolean; - fieldsPerRecord?: number; -} - -function chkOptions(opt: ReadOptions): void { - if (!opt.separator) { - opt.separator = ","; - } - if (!opt.trimLeadingSpace) { - opt.trimLeadingSpace = false; - } - if ( - INVALID_RUNE.includes(opt.separator) || - (typeof opt.comment === "string" && INVALID_RUNE.includes(opt.comment)) || - opt.separator === opt.comment - ) { - throw new Error(ERR_INVALID_DELIM); - } -} - -async function readRecord( - startLine: number, - reader: BufReader, - opt: ReadOptions = { separator: ",", trimLeadingSpace: false }, -): Promise<string[] | null> { - const tp = new TextProtoReader(reader); - let line = await readLine(tp); - let lineIndex = startLine + 1; - - if (line === null) return null; - if (line.length === 0) { - return []; - } - // line starting with comment character is ignored - if (opt.comment && line[0] === opt.comment) { - return []; - } - - assert(opt.separator != null); - - let fullLine = line; - let quoteError: ParseError | null = null; - const quote = '"'; - const quoteLen = quote.length; - const separatorLen = opt.separator.length; - let recordBuffer = ""; - const fieldIndexes = [] as number[]; - parseField: - for (;;) { - if (opt.trimLeadingSpace) { - line = line.trimLeft(); - } - - if (line.length === 0 || !line.startsWith(quote)) { - // Non-quoted string field - const i = line.indexOf(opt.separator); - let field = line; - if (i >= 0) { - field = field.substring(0, i); - } - // Check to make sure a quote does not appear in field. - if (!opt.lazyQuotes) { - const j = field.indexOf(quote); - if (j >= 0) { - const col = runeCount( - fullLine.slice(0, fullLine.length - line.slice(j).length), - ); - quoteError = new ParseError( - startLine + 1, - lineIndex, - col, - ERR_BARE_QUOTE, - ); - break parseField; - } - } - recordBuffer += field; - fieldIndexes.push(recordBuffer.length); - if (i >= 0) { - line = line.substring(i + separatorLen); - continue parseField; - } - break parseField; - } else { - // Quoted string field - line = line.substring(quoteLen); - for (;;) { - const i = line.indexOf(quote); - if (i >= 0) { - // Hit next quote. - recordBuffer += line.substring(0, i); - line = line.substring(i + quoteLen); - if (line.startsWith(quote)) { - // `""` sequence (append quote). - recordBuffer += quote; - line = line.substring(quoteLen); - } else if (line.startsWith(opt.separator)) { - // `","` sequence (end of field). - line = line.substring(separatorLen); - fieldIndexes.push(recordBuffer.length); - continue parseField; - } else if (0 === line.length) { - // `"\n` sequence (end of line). - fieldIndexes.push(recordBuffer.length); - break parseField; - } else if (opt.lazyQuotes) { - // `"` sequence (bare quote). - recordBuffer += quote; - } else { - // `"*` sequence (invalid non-escaped quote). - const col = runeCount( - fullLine.slice(0, fullLine.length - line.length - quoteLen), - ); - quoteError = new ParseError( - startLine + 1, - lineIndex, - col, - ERR_QUOTE, - ); - break parseField; - } - } else if (line.length > 0 || !(await isEOF(tp))) { - // Hit end of line (copy all data so far). - recordBuffer += line; - const r = await readLine(tp); - lineIndex++; - line = r ?? ""; // This is a workaround for making this module behave similarly to the encoding/csv/reader.go. - fullLine = line; - if (r === null) { - // Abrupt end of file (EOF or error). - if (!opt.lazyQuotes) { - const col = runeCount(fullLine); - quoteError = new ParseError( - startLine + 1, - lineIndex, - col, - ERR_QUOTE, - ); - break parseField; - } - fieldIndexes.push(recordBuffer.length); - break parseField; - } - recordBuffer += "\n"; // preserve line feed (This is because TextProtoReader removes it.) - } else { - // Abrupt end of file (EOF on error). - if (!opt.lazyQuotes) { - const col = runeCount(fullLine); - quoteError = new ParseError( - startLine + 1, - lineIndex, - col, - ERR_QUOTE, - ); - break parseField; - } - fieldIndexes.push(recordBuffer.length); - break parseField; - } - } - } - } - if (quoteError) { - throw quoteError; - } - const result = [] as string[]; - let preIdx = 0; - for (const i of fieldIndexes) { - result.push(recordBuffer.slice(preIdx, i)); - preIdx = i; - } - return result; -} - -async function isEOF(tp: TextProtoReader): Promise<boolean> { - return (await tp.r.peek(0)) === null; -} - -function runeCount(s: string): number { - // Array.from considers the surrogate pair. - return Array.from(s).length; -} - -async function readLine(tp: TextProtoReader): Promise<string | null> { - let line: string; - const r = await tp.readLine(); - if (r === null) return null; - line = r; - - // For backwards compatibility, drop trailing \r before EOF. - if ((await isEOF(tp)) && line.length > 0 && line[line.length - 1] === "\r") { - line = line.substring(0, line.length - 1); - } - - // Normalize \r\n to \n on all input lines. - if ( - line.length >= 2 && - line[line.length - 2] === "\r" && - line[line.length - 1] === "\n" - ) { - line = line.substring(0, line.length - 2); - line = line + "\n"; - } - - return line; -} - -/** - * Parse the CSV from the `reader` with the options provided and return `string[][]`. - * - * @param reader provides the CSV data to parse - * @param opt controls the parsing behavior - */ -export async function readMatrix( - reader: BufReader, - opt: ReadOptions = { - separator: ",", - trimLeadingSpace: false, - lazyQuotes: false, - }, -): Promise<string[][]> { - const result: string[][] = []; - let _nbFields: number | undefined; - let lineResult: string[]; - let first = true; - let lineIndex = 0; - chkOptions(opt); - - for (;;) { - const r = await readRecord(lineIndex, reader, opt); - if (r === null) break; - lineResult = r; - lineIndex++; - // If fieldsPerRecord is 0, Read sets it to - // the number of fields in the first record - if (first) { - first = false; - if (opt.fieldsPerRecord !== undefined) { - if (opt.fieldsPerRecord === 0) { - _nbFields = lineResult.length; - } else { - _nbFields = opt.fieldsPerRecord; - } - } - } - - if (lineResult.length > 0) { - if (_nbFields && _nbFields !== lineResult.length) { - throw new ParseError(lineIndex, lineIndex, null, ERR_FIELD_COUNT); - } - result.push(lineResult); - } - } - return result; -} - -/** - * Parse the CSV string/buffer with the options provided. - * - * ColumnOptions provides the column definition - * and the parse function for each entry of the - * column. - */ -export interface ColumnOptions { - /** - * Name of the column to be used as property - */ - name: string; - /** - * Parse function for the column. - * This is executed on each entry of the header. - * This can be combined with the Parse function of the rows. - */ - parse?: (input: string) => unknown; -} - -export interface ParseOptions extends ReadOptions { - /** - * If you provide `skipFirstRow: true` and `columns`, the first line will be skipped. - * If you provide `skipFirstRow: true` but not `columns`, the first line will be skipped and used as header definitions. - */ - skipFirstRow?: boolean; - - /** - * If you provide `string[]` or `ColumnOptions[]`, those names will be used for header definition. - */ - columns?: string[] | ColumnOptions[]; - - /** Parse function for rows. - * Example: - * const r = await parseFile('a,b,c\ne,f,g\n', { - * columns: ["this", "is", "sparta"], - * parse: (e: Record<string, unknown>) => { - * return { super: e.this, street: e.is, fighter: e.sparta }; - * } - * }); - * // output - * [ - * { super: "a", street: "b", fighter: "c" }, - * { super: "e", street: "f", fighter: "g" } - * ] - */ - parse?: (input: unknown) => unknown; -} - -/** - * Csv parse helper to manipulate data. - * Provides an auto/custom mapper for columns and parse function - * for columns and rows. - * @param input Input to parse. Can be a string or BufReader. - * @param opt options of the parser. - * @returns If you don't provide `opt.skipFirstRow`, `opt.parse`, and `opt.columns`, it returns `string[][]`. - * If you provide `opt.skipFirstRow` or `opt.columns` but not `opt.parse`, it returns `object[]`. - * If you provide `opt.parse`, it returns an array where each element is the value returned from `opt.parse`. - */ -export async function parse( - input: string | BufReader, - opt: ParseOptions = { - skipFirstRow: false, - }, -): Promise<unknown[]> { - let r: string[][]; - if (input instanceof BufReader) { - r = await readMatrix(input, opt); - } else { - r = await readMatrix(new BufReader(new StringReader(input)), opt); - } - if (opt.skipFirstRow || opt.columns) { - let headers: ColumnOptions[] = []; - let i = 0; - - if (opt.skipFirstRow) { - const head = r.shift(); - assert(head != null); - headers = head.map( - (e): ColumnOptions => { - return { - name: e, - }; - }, - ); - i++; - } - - if (opt.columns) { - if (typeof opt.columns[0] !== "string") { - headers = opt.columns as ColumnOptions[]; - } else { - const h = opt.columns as string[]; - headers = h.map( - (e): ColumnOptions => { - return { - name: e, - }; - }, - ); - } - } - return r.map((e): unknown => { - if (e.length !== headers.length) { - throw `Error number of fields line:${i}`; - } - i++; - const out: Record<string, unknown> = {}; - for (let j = 0; j < e.length; j++) { - const h = headers[j]; - if (h.parse) { - out[h.name] = h.parse(e[j]); - } else { - out[h.name] = e[j]; - } - } - if (opt.parse) { - return opt.parse(out); - } - return out; - }); - } - if (opt.parse) { - return r.map((e: string[]): unknown => { - assert(opt.parse, "opt.parse must be set"); - return opt.parse(e); - }); - } - return r; -} diff --git a/std/encoding/csv_stringify.ts b/std/encoding/csv_stringify.ts deleted file mode 100644 index 921631d37..000000000 --- a/std/encoding/csv_stringify.ts +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -// Implements the CSV spec at https://tools.ietf.org/html/rfc4180 - -// This module is browser compatible. - -const QUOTE = '"'; -export const NEWLINE = "\r\n"; - -export class StringifyError extends Error { - readonly name = "StringifyError"; -} - -function getEscapedString(value: unknown, sep: string): string { - if (value === undefined || value === null) return ""; - let str = ""; - - if (typeof value === "object") str = JSON.stringify(value); - else str = String(value); - - // Is regex.test more performant here? If so, how to dynamically create? - // https://stackoverflow.com/questions/3561493/ - if (str.includes(sep) || str.includes(NEWLINE) || str.includes(QUOTE)) { - return `${QUOTE}${str.replaceAll(QUOTE, `${QUOTE}${QUOTE}`)}${QUOTE}`; - } - - return str; -} - -type PropertyAccessor = number | string; - -/** - * @param fn Optional callback for transforming the value - * - * @param header Explicit column header name. If omitted, - * the (final) property accessor is used for this value. - * - * @param prop Property accessor(s) used to access the value on the object - */ -export type ColumnDetails = { - // "unknown" is more type-safe, but inconvenient for user. How to resolve? - // deno-lint-ignore no-explicit-any - fn?: (value: any) => string | Promise<string>; - header?: string; - prop: PropertyAccessor | PropertyAccessor[]; -}; - -export type Column = ColumnDetails | PropertyAccessor | PropertyAccessor[]; - -type NormalizedColumn = Omit<ColumnDetails, "header" | "prop"> & { - header: string; - prop: PropertyAccessor[]; -}; - -function normalizeColumn(column: Column): NormalizedColumn { - let fn: NormalizedColumn["fn"], - header: NormalizedColumn["header"], - prop: NormalizedColumn["prop"]; - - if (typeof column === "object") { - if (Array.isArray(column)) { - header = String(column[column.length - 1]); - prop = column; - } else { - ({ fn } = column); - prop = Array.isArray(column.prop) ? column.prop : [column.prop]; - header = typeof column.header === "string" - ? column.header - : String(prop[prop.length - 1]); - } - } else { - header = String(column); - prop = [column]; - } - - return { fn, header, prop }; -} - -type ObjectWithStringPropertyKeys = Record<string, unknown>; - -/** An object (plain or array) */ -export type DataItem = ObjectWithStringPropertyKeys | unknown[]; - -/** - * Returns an array of values from an object using the property accessors - * (and optional transform function) in each column - */ -async function getValuesFromItem( - item: DataItem, - normalizedColumns: NormalizedColumn[], -): Promise<unknown[]> { - const values: unknown[] = []; - - for (const column of normalizedColumns) { - let value: unknown = item; - - for (const prop of column.prop) { - if (typeof value !== "object" || value === null) continue; - if (Array.isArray(value)) { - if (typeof prop === "number") value = value[prop]; - else { - throw new StringifyError('Property accessor is not of type "number"'); - } - } // I think this assertion is safe. Confirm? - else value = (value as ObjectWithStringPropertyKeys)[prop]; - } - - if (typeof column.fn === "function") value = await column.fn(value); - values.push(value); - } - - return values; -} - -/** - * @param headers Whether or not to include the row of headers. - * Default: `true` - * - * @param separator Delimiter used to separate values. Examples: - * - `","` _comma_ (Default) - * - `"\t"` _tab_ - * - `"|"` _pipe_ - * - etc. - */ -export type StringifyOptions = { - headers?: boolean; - separator?: string; -}; - -/** - * @param data The array of objects to encode - * @param columns Array of values specifying which data to include in the output - * @param options Output formatting options - */ -export async function stringify( - data: DataItem[], - columns: Column[], - options: StringifyOptions = {}, -): Promise<string> { - const { headers, separator: sep } = { - headers: true, - separator: ",", - ...options, - }; - if (sep.includes(QUOTE) || sep.includes(NEWLINE)) { - const message = [ - "Separator cannot include the following strings:", - ' - U+0022: Quotation mark (")', - " - U+000D U+000A: Carriage Return + Line Feed (\\r\\n)", - ].join("\n"); - throw new StringifyError(message); - } - - const normalizedColumns = columns.map(normalizeColumn); - let output = ""; - - if (headers) { - output += normalizedColumns - .map((column) => getEscapedString(column.header, sep)) - .join(sep); - output += NEWLINE; - } - - for (const item of data) { - const values = await getValuesFromItem(item, normalizedColumns); - output += values - .map((value) => getEscapedString(value, sep)) - .join(sep); - output += NEWLINE; - } - - return output; -} diff --git a/std/encoding/csv_stringify_test.ts b/std/encoding/csv_stringify_test.ts deleted file mode 100644 index f8b7d81cd..000000000 --- a/std/encoding/csv_stringify_test.ts +++ /dev/null @@ -1,373 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -import { assertEquals, assertThrowsAsync } from "../testing/asserts.ts"; - -import { - Column, - DataItem, - NEWLINE, - stringify, - StringifyError, - StringifyOptions, -} from "./csv_stringify.ts"; - -type StringifyTestCaseBase = { - columns: Column[]; - data: DataItem[]; - name: string; - options?: StringifyOptions; -}; - -type StringifyTestCaseError = StringifyTestCaseBase & { - errorMessage?: string; - // deno-lint-ignore no-explicit-any - throwsError: new (...args: any[]) => Error; -}; - -type StringifyTestCase = StringifyTestCaseBase & { expected: string }; - -const stringifyTestCases: (StringifyTestCase | StringifyTestCaseError)[] = [ - { - columns: ["a"], - data: [["foo"], ["bar"]], - errorMessage: 'Property accessor is not of type "number"', - name: "[CSV_stringify] Access array index using string", - throwsError: StringifyError, - }, - { - columns: [0], - data: [["foo"], ["bar"]], - errorMessage: [ - "Separator cannot include the following strings:", - ' - U+0022: Quotation mark (")', - " - U+000D U+000A: Carriage Return + Line Feed (\\r\\n)", - ].join("\n"), - name: "[CSV_stringify] Double quote in separator", - options: { separator: '"' }, - throwsError: StringifyError, - }, - { - columns: [0], - data: [["foo"], ["bar"]], - errorMessage: [ - "Separator cannot include the following strings:", - ' - U+0022: Quotation mark (")', - " - U+000D U+000A: Carriage Return + Line Feed (\\r\\n)", - ].join("\n"), - name: "[CSV_stringify] CRLF in separator", - options: { separator: "\r\n" }, - throwsError: StringifyError, - }, - { - columns: [ - { - fn: (obj) => obj.toUpperCase(), - prop: "msg", - }, - ], - data: [{ msg: { value: "foo" } }, { msg: { value: "bar" } }], - name: "[CSV_stringify] Transform function", - throwsError: TypeError, - }, - { - columns: [], - data: [], - expected: NEWLINE, - name: "[CSV_stringify] No data, no columns", - }, - { - columns: [], - data: [], - expected: ``, - name: "[CSV_stringify] No data, no columns, no headers", - options: { headers: false }, - }, - { - columns: ["a"], - data: [], - expected: `a${NEWLINE}`, - name: "[CSV_stringify] No data, columns", - }, - { - columns: ["a"], - data: [], - expected: ``, - name: "[CSV_stringify] No data, columns, no headers", - options: { headers: false }, - }, - { - columns: [], - data: [{ a: 1 }, { a: 2 }], - expected: `${NEWLINE}${NEWLINE}${NEWLINE}`, - name: "[CSV_stringify] Data, no columns", - }, - { - columns: [0, 1], - data: [["foo", "bar"], ["baz", "qux"]], - expected: `0\r1${NEWLINE}foo\rbar${NEWLINE}baz\rqux${NEWLINE}`, - name: "[CSV_stringify] Separator: CR", - options: { separator: "\r" }, - }, - { - columns: [0, 1], - data: [["foo", "bar"], ["baz", "qux"]], - expected: `0\n1${NEWLINE}foo\nbar${NEWLINE}baz\nqux${NEWLINE}`, - name: "[CSV_stringify] Separator: LF", - options: { separator: "\n" }, - }, - { - columns: [1], - data: [{ 1: 1 }, { 1: 2 }], - expected: `1${NEWLINE}1${NEWLINE}2${NEWLINE}`, - name: "[CSV_stringify] Column: number accessor, Data: object", - }, - { - columns: [{ header: "Value", prop: "value" }], - data: [{ value: "foo" }, { value: "bar" }], - expected: `foo${NEWLINE}bar${NEWLINE}`, - name: "[CSV_stringify] Explicit header value, no headers", - options: { headers: false }, - }, - { - columns: [1], - data: [["key", "foo"], ["key", "bar"]], - expected: `1${NEWLINE}foo${NEWLINE}bar${NEWLINE}`, - name: "[CSV_stringify] Column: number accessor, Data: array", - }, - { - columns: [[1]], - data: [{ 1: 1 }, { 1: 2 }], - expected: `1${NEWLINE}1${NEWLINE}2${NEWLINE}`, - name: "[CSV_stringify] Column: array number accessor, Data: object", - }, - { - columns: [[1]], - data: [["key", "foo"], ["key", "bar"]], - expected: `1${NEWLINE}foo${NEWLINE}bar${NEWLINE}`, - name: "[CSV_stringify] Column: array number accessor, Data: array", - }, - { - columns: [[1, 1]], - data: [["key", ["key", "foo"]], ["key", ["key", "bar"]]], - expected: `1${NEWLINE}foo${NEWLINE}bar${NEWLINE}`, - name: "[CSV_stringify] Column: array number accessor, Data: array", - }, - { - columns: ["value"], - data: [{ value: "foo" }, { value: "bar" }], - expected: `value${NEWLINE}foo${NEWLINE}bar${NEWLINE}`, - name: "[CSV_stringify] Column: string accessor, Data: object", - }, - { - columns: [["value"]], - data: [{ value: "foo" }, { value: "bar" }], - expected: `value${NEWLINE}foo${NEWLINE}bar${NEWLINE}`, - name: "[CSV_stringify] Column: array string accessor, Data: object", - }, - { - columns: [["msg", "value"]], - data: [{ msg: { value: "foo" } }, { msg: { value: "bar" } }], - expected: `value${NEWLINE}foo${NEWLINE}bar${NEWLINE}`, - name: "[CSV_stringify] Column: array string accessor, Data: object", - }, - { - columns: [ - { - header: "Value", - prop: ["msg", "value"], - }, - ], - data: [{ msg: { value: "foo" } }, { msg: { value: "bar" } }], - expected: `Value${NEWLINE}foo${NEWLINE}bar${NEWLINE}`, - name: "[CSV_stringify] Explicit header", - }, - { - columns: [ - { - fn: (str: string) => str.toUpperCase(), - prop: ["msg", "value"], - }, - ], - data: [{ msg: { value: "foo" } }, { msg: { value: "bar" } }], - expected: `value${NEWLINE}FOO${NEWLINE}BAR${NEWLINE}`, - name: "[CSV_stringify] Transform function 1", - }, - { - columns: [ - { - fn: (str: string) => Promise.resolve(str.toUpperCase()), - prop: ["msg", "value"], - }, - ], - data: [{ msg: { value: "foo" } }, { msg: { value: "bar" } }], - expected: `value${NEWLINE}FOO${NEWLINE}BAR${NEWLINE}`, - name: "[CSV_stringify] Transform function 1 async", - }, - { - columns: [ - { - fn: (obj: { value: string }) => obj.value, - prop: "msg", - }, - ], - data: [{ msg: { value: "foo" } }, { msg: { value: "bar" } }], - expected: `msg${NEWLINE}foo${NEWLINE}bar${NEWLINE}`, - name: "[CSV_stringify] Transform function 2", - }, - { - columns: [ - { - fn: (obj: { value: string }) => obj.value, - header: "Value", - prop: "msg", - }, - ], - data: [{ msg: { value: "foo" } }, { msg: { value: "bar" } }], - expected: `Value${NEWLINE}foo${NEWLINE}bar${NEWLINE}`, - name: "[CSV_stringify] Transform function 2, explicit header", - }, - { - columns: [0], - data: [[{ value: "foo" }], [{ value: "bar" }]], - expected: - `0${NEWLINE}"{""value"":""foo""}"${NEWLINE}"{""value"":""bar""}"${NEWLINE}`, - name: "[CSV_stringify] Targeted value: object", - }, - { - columns: [0], - data: [ - [[{ value: "foo" }, { value: "bar" }]], - [[{ value: "baz" }, { value: "qux" }]], - ], - expected: - `0${NEWLINE}"[{""value"":""foo""},{""value"":""bar""}]"${NEWLINE}"[{""value"":""baz""},{""value"":""qux""}]"${NEWLINE}`, - name: "[CSV_stringify] Targeted value: arary of objects", - }, - { - columns: [0], - data: [[["foo", "bar"]], [["baz", "qux"]]], - expected: - `0${NEWLINE}"[""foo"",""bar""]"${NEWLINE}"[""baz"",""qux""]"${NEWLINE}`, - name: "[CSV_stringify] Targeted value: array", - }, - { - columns: [0], - data: [[["foo", "bar"]], [["baz", "qux"]]], - expected: - `0${NEWLINE}"[""foo"",""bar""]"${NEWLINE}"[""baz"",""qux""]"${NEWLINE}`, - name: "[CSV_stringify] Targeted value: array, separator: tab", - options: { separator: "\t" }, - }, - { - columns: [0], - data: [[], []], - expected: `0${NEWLINE}${NEWLINE}${NEWLINE}`, - name: "[CSV_stringify] Targeted value: undefined", - }, - { - columns: [0], - data: [[null], [null]], - expected: `0${NEWLINE}${NEWLINE}${NEWLINE}`, - name: "[CSV_stringify] Targeted value: null", - }, - { - columns: [0], - data: [[0xa], [0xb]], - expected: `0${NEWLINE}10${NEWLINE}11${NEWLINE}`, - name: "[CSV_stringify] Targeted value: hex number", - }, - { - columns: [0], - data: [[BigInt("1")], [BigInt("2")]], - expected: `0${NEWLINE}1${NEWLINE}2${NEWLINE}`, - name: "[CSV_stringify] Targeted value: BigInt", - }, - { - columns: [0], - data: [[true], [false]], - expected: `0${NEWLINE}true${NEWLINE}false${NEWLINE}`, - name: "[CSV_stringify] Targeted value: boolean", - }, - { - columns: [0], - data: [["foo"], ["bar"]], - expected: `0${NEWLINE}foo${NEWLINE}bar${NEWLINE}`, - name: "[CSV_stringify] Targeted value: string", - }, - { - columns: [0], - data: [[Symbol("foo")], [Symbol("bar")]], - expected: `0${NEWLINE}Symbol(foo)${NEWLINE}Symbol(bar)${NEWLINE}`, - name: "[CSV_stringify] Targeted value: symbol", - }, - { - columns: [0], - data: [[(n: number) => n]], - expected: `0${NEWLINE}(n) => n${NEWLINE}`, - name: "[CSV_stringify] Targeted value: function", - }, - { - columns: [0], - data: [['foo"']], - expected: `0${NEWLINE}"foo"""${NEWLINE}`, - name: "[CSV_stringify] Value with double quote", - }, - { - columns: [0], - data: [["foo\r\n"]], - expected: `0${NEWLINE}"foo\r\n"${NEWLINE}`, - name: "[CSV_stringify] Value with CRLF", - }, - { - columns: [0], - data: [["foo\r"]], - expected: `0${NEWLINE}foo\r${NEWLINE}`, - name: "[CSV_stringify] Value with CR", - }, - { - columns: [0], - data: [["foo\n"]], - expected: `0${NEWLINE}foo\n${NEWLINE}`, - name: "[CSV_stringify] Value with LF", - }, - { - columns: [0], - data: [["foo,"]], - expected: `0${NEWLINE}"foo,"${NEWLINE}`, - name: "[CSV_stringify] Value with comma", - }, - { - columns: [0], - data: [["foo,"]], - expected: `0${NEWLINE}foo,${NEWLINE}`, - name: "[CSV_stringify] Value with comma, tab separator", - options: { separator: "\t" }, - }, -]; - -for (const tc of stringifyTestCases) { - if ((tc as StringifyTestCaseError).throwsError) { - const t = tc as StringifyTestCaseError; - Deno.test({ - async fn() { - await assertThrowsAsync( - async () => { - await stringify(t.data, t.columns, t.options); - }, - t.throwsError, - t.errorMessage, - ); - }, - name: t.name, - }); - } else { - const t = tc as StringifyTestCase; - Deno.test({ - async fn() { - const actual = await stringify(t.data, t.columns, t.options); - assertEquals(actual, t.expected); - }, - name: t.name, - }); - } -} diff --git a/std/encoding/csv_test.ts b/std/encoding/csv_test.ts deleted file mode 100644 index c3257808f..000000000 --- a/std/encoding/csv_test.ts +++ /dev/null @@ -1,653 +0,0 @@ -// Test ported from Golang -// https://github.com/golang/go/blob/2cc15b1/src/encoding/csv/reader_test.go -// Copyright 2011 The Go Authors. All rights reserved. BSD license. -// https://github.com/golang/go/blob/master/LICENSE -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -import { assertEquals, assertThrowsAsync } from "../testing/asserts.ts"; -import { - ERR_BARE_QUOTE, - ERR_FIELD_COUNT, - ERR_INVALID_DELIM, - ERR_QUOTE, - parse, - ParseError, - readMatrix, -} from "./csv.ts"; -import { StringReader } from "../io/readers.ts"; -import { BufReader } from "../io/bufio.ts"; - -// Test cases for `readMatrix()` -const testCases = [ - { - Name: "Simple", - Input: "a,b,c\n", - Output: [["a", "b", "c"]], - }, - { - Name: "CRLF", - Input: "a,b\r\nc,d\r\n", - Output: [ - ["a", "b"], - ["c", "d"], - ], - }, - { - Name: "BareCR", - Input: "a,b\rc,d\r\n", - Output: [["a", "b\rc", "d"]], - }, - { - Name: "RFC4180test", - Input: `#field1,field2,field3 -"aaa","bbb","ccc" -"a,a","bbb","ccc" -zzz,yyy,xxx`, - UseFieldsPerRecord: true, - FieldsPerRecord: 0, - Output: [ - ["#field1", "field2", "field3"], - ["aaa", "bbb", "ccc"], - ["a,a", `bbb`, "ccc"], - ["zzz", "yyy", "xxx"], - ], - }, - { - Name: "NoEOLTest", - Input: "a,b,c", - Output: [["a", "b", "c"]], - }, - { - Name: "Semicolon", - Input: "a;b;c\n", - Output: [["a", "b", "c"]], - Separator: ";", - }, - { - Name: "MultiLine", - Input: `"two -line","one line","three -line -field"`, - Output: [["two\nline", "one line", "three\nline\nfield"]], - }, - { - Name: "BlankLine", - Input: "a,b,c\n\nd,e,f\n\n", - Output: [ - ["a", "b", "c"], - ["d", "e", "f"], - ], - }, - { - Name: "BlankLineFieldCount", - Input: "a,b,c\n\nd,e,f\n\n", - Output: [ - ["a", "b", "c"], - ["d", "e", "f"], - ], - UseFieldsPerRecord: true, - FieldsPerRecord: 0, - }, - { - Name: "TrimSpace", - Input: " a, b, c\n", - Output: [["a", "b", "c"]], - TrimLeadingSpace: true, - }, - { - Name: "LeadingSpace", - Input: " a, b, c\n", - Output: [[" a", " b", " c"]], - }, - { - Name: "Comment", - Input: "#1,2,3\na,b,c\n#comment", - Output: [["a", "b", "c"]], - Comment: "#", - }, - { - Name: "NoComment", - Input: "#1,2,3\na,b,c", - Output: [ - ["#1", "2", "3"], - ["a", "b", "c"], - ], - }, - { - Name: "LazyQuotes", - Input: `a "word","1"2",a","b`, - Output: [[`a "word"`, `1"2`, `a"`, `b`]], - LazyQuotes: true, - }, - { - Name: "BareQuotes", - Input: `a "word","1"2",a"`, - Output: [[`a "word"`, `1"2`, `a"`]], - LazyQuotes: true, - }, - { - Name: "BareDoubleQuotes", - Input: `a""b,c`, - Output: [[`a""b`, `c`]], - LazyQuotes: true, - }, - { - Name: "BadDoubleQuotes", - Input: `a""b,c`, - Error: new ParseError(1, 1, 1, ERR_BARE_QUOTE), - }, - { - Name: "TrimQuote", - Input: ` "a"," b",c`, - Output: [["a", " b", "c"]], - TrimLeadingSpace: true, - }, - { - Name: "BadBareQuote", - Input: `a "word","b"`, - Error: new ParseError(1, 1, 2, ERR_BARE_QUOTE), - }, - { - Name: "BadTrailingQuote", - Input: `"a word",b"`, - Error: new ParseError(1, 1, 10, ERR_BARE_QUOTE), - }, - { - Name: "ExtraneousQuote", - Input: `"a "word","b"`, - Error: new ParseError(1, 1, 3, ERR_QUOTE), - }, - { - Name: "BadFieldCount", - Input: "a,b,c\nd,e", - Error: new ParseError(2, 2, null, ERR_FIELD_COUNT), - UseFieldsPerRecord: true, - FieldsPerRecord: 0, - }, - { - Name: "BadFieldCount1", - Input: `a,b,c`, - UseFieldsPerRecord: true, - FieldsPerRecord: 2, - Error: new ParseError(1, 1, null, ERR_FIELD_COUNT), - }, - { - Name: "FieldCount", - Input: "a,b,c\nd,e", - Output: [ - ["a", "b", "c"], - ["d", "e"], - ], - }, - { - Name: "TrailingCommaEOF", - Input: "a,b,c,", - Output: [["a", "b", "c", ""]], - }, - { - Name: "TrailingCommaEOL", - Input: "a,b,c,\n", - Output: [["a", "b", "c", ""]], - }, - { - Name: "TrailingCommaSpaceEOF", - Input: "a,b,c, ", - Output: [["a", "b", "c", ""]], - TrimLeadingSpace: true, - }, - { - Name: "TrailingCommaSpaceEOL", - Input: "a,b,c, \n", - Output: [["a", "b", "c", ""]], - TrimLeadingSpace: true, - }, - { - Name: "TrailingCommaLine3", - Input: "a,b,c\nd,e,f\ng,hi,", - Output: [ - ["a", "b", "c"], - ["d", "e", "f"], - ["g", "hi", ""], - ], - TrimLeadingSpace: true, - }, - { - Name: "NotTrailingComma3", - Input: "a,b,c, \n", - Output: [["a", "b", "c", " "]], - }, - { - Name: "CommaFieldTest", - Input: `x,y,z,w -x,y,z, -x,y,, -x,,, -,,, -"x","y","z","w" -"x","y","z","" -"x","y","","" -"x","","","" -"","","","" -`, - Output: [ - ["x", "y", "z", "w"], - ["x", "y", "z", ""], - ["x", "y", "", ""], - ["x", "", "", ""], - ["", "", "", ""], - ["x", "y", "z", "w"], - ["x", "y", "z", ""], - ["x", "y", "", ""], - ["x", "", "", ""], - ["", "", "", ""], - ], - }, - { - Name: "TrailingCommaIneffective1", - Input: "a,b,\nc,d,e", - Output: [ - ["a", "b", ""], - ["c", "d", "e"], - ], - TrimLeadingSpace: true, - }, - { - Name: "ReadAllReuseRecord", - Input: "a,b\nc,d", - Output: [ - ["a", "b"], - ["c", "d"], - ], - ReuseRecord: true, - }, - { - Name: "StartLine1", // Issue 19019 - Input: 'a,"b\nc"d,e', - Error: new ParseError(1, 2, 1, ERR_QUOTE), - }, - { - Name: "StartLine2", - Input: 'a,b\n\"d\n\n,e', - Error: new ParseError(2, 5, 0, ERR_QUOTE), - }, - { - Name: "CRLFInQuotedField", // Issue 21201 - Input: 'A,"Hello\r\nHi",B\r\n', - Output: [["A", "Hello\nHi", "B"]], - }, - { - Name: "BinaryBlobField", // Issue 19410 - Input: "x09\x41\xb4\x1c,aktau", - Output: [["x09A\xb4\x1c", "aktau"]], - }, - { - Name: "TrailingCR", - Input: "field1,field2\r", - Output: [["field1", "field2"]], - }, - { - Name: "QuotedTrailingCR", - Input: '"field"\r', - Output: [["field"]], - }, - { - Name: "QuotedTrailingCRCR", - Input: '"field"\r\r', - Error: new ParseError(1, 1, 6, ERR_QUOTE), - }, - { - Name: "FieldCR", - Input: "field\rfield\r", - Output: [["field\rfield"]], - }, - { - Name: "FieldCRCR", - Input: "field\r\rfield\r\r", - Output: [["field\r\rfield\r"]], - }, - { - Name: "FieldCRCRLF", - Input: "field\r\r\nfield\r\r\n", - Output: [["field\r"], ["field\r"]], - }, - { - Name: "FieldCRCRLFCR", - Input: "field\r\r\n\rfield\r\r\n\r", - Output: [["field\r"], ["\rfield\r"]], - }, - { - Name: "FieldCRCRLFCRCR", - Input: "field\r\r\n\r\rfield\r\r\n\r\r", - Output: [["field\r"], ["\r\rfield\r"], ["\r"]], - }, - { - Name: "MultiFieldCRCRLFCRCR", - Input: "field1,field2\r\r\n\r\rfield1,field2\r\r\n\r\r,", - Output: [ - ["field1", "field2\r"], - ["\r\rfield1", "field2\r"], - ["\r\r", ""], - ], - }, - { - Name: "NonASCIICommaAndComment", - Input: "a£b,c£ \td,e\n€ comment\n", - Output: [["a", "b,c", "d,e"]], - TrimLeadingSpace: true, - Separator: "£", - Comment: "€", - }, - { - Name: "NonASCIICommaAndCommentWithQuotes", - Input: 'a€" b,"€ c\nλ comment\n', - Output: [["a", " b,", " c"]], - Separator: "€", - Comment: "λ", - }, - { - // λ and θ start with the same byte. - // This tests that the parser doesn't confuse such characters. - Name: "NonASCIICommaConfusion", - Input: '"abθcd"λefθgh', - Output: [["abθcd", "efθgh"]], - Separator: "λ", - Comment: "€", - }, - { - Name: "NonASCIICommentConfusion", - Input: "λ\nλ\nθ\nλ\n", - Output: [["λ"], ["λ"], ["λ"]], - Comment: "θ", - }, - { - Name: "QuotedFieldMultipleLF", - Input: '"\n\n\n\n"', - Output: [["\n\n\n\n"]], - }, - { - Name: "MultipleCRLF", - Input: "\r\n\r\n\r\n\r\n", - Output: [], - }, - /** - * The implementation may read each line in several chunks if - * it doesn't fit entirely. - * in the read buffer, so we should test the code to handle that condition. - */ - { - Name: "HugeLines", - Input: "#ignore\n".repeat(10000) + "@".repeat(5000) + "," + - "*".repeat(5000), - Output: [["@".repeat(5000), "*".repeat(5000)]], - Comment: "#", - }, - { - Name: "QuoteWithTrailingCRLF", - Input: '"foo"bar"\r\n', - Error: new ParseError(1, 1, 4, ERR_QUOTE), - }, - { - Name: "LazyQuoteWithTrailingCRLF", - Input: '"foo"bar"\r\n', - Output: [[`foo"bar`]], - LazyQuotes: true, - }, - { - Name: "DoubleQuoteWithTrailingCRLF", - Input: '"foo""bar"\r\n', - Output: [[`foo"bar`]], - }, - { - Name: "EvenQuotes", - Input: `""""""""`, - Output: [[`"""`]], - }, - { - Name: "OddQuotes", - Input: `"""""""`, - Error: new ParseError(1, 1, 7, ERR_QUOTE), - }, - { - Name: "LazyOddQuotes", - Input: `"""""""`, - Output: [[`"""`]], - LazyQuotes: true, - }, - { - Name: "BadComma1", - Separator: "\n", - Error: new Error(ERR_INVALID_DELIM), - }, - { - Name: "BadComma2", - Separator: "\r", - Error: new Error(ERR_INVALID_DELIM), - }, - { - Name: "BadComma3", - Separator: '"', - Error: new Error(ERR_INVALID_DELIM), - }, - { - Name: "BadComment1", - Comment: "\n", - Error: new Error(ERR_INVALID_DELIM), - }, - { - Name: "BadComment2", - Comment: "\r", - Error: new Error(ERR_INVALID_DELIM), - }, - { - Name: "BadCommaComment", - Separator: "X", - Comment: "X", - Error: new Error(ERR_INVALID_DELIM), - }, -]; -for (const t of testCases) { - Deno.test({ - name: `[CSV] ${t.Name}`, - async fn(): Promise<void> { - let separator = ","; - let comment: string | undefined; - let fieldsPerRec: number | undefined; - let trim = false; - let lazyquote = false; - if (t.Separator) { - separator = t.Separator; - } - if (t.Comment) { - comment = t.Comment; - } - if (t.TrimLeadingSpace) { - trim = true; - } - if (t.UseFieldsPerRecord) { - fieldsPerRec = t.FieldsPerRecord; - } - if (t.LazyQuotes) { - lazyquote = t.LazyQuotes; - } - let actual; - if (t.Error) { - const err = await assertThrowsAsync(async () => { - await readMatrix( - new BufReader(new StringReader(t.Input ?? "")), - { - separator, - comment: comment, - trimLeadingSpace: trim, - fieldsPerRecord: fieldsPerRec, - lazyQuotes: lazyquote, - }, - ); - }); - - assertEquals(err, t.Error); - } else { - actual = await readMatrix( - new BufReader(new StringReader(t.Input ?? "")), - { - separator, - comment: comment, - trimLeadingSpace: trim, - fieldsPerRecord: fieldsPerRec, - lazyQuotes: lazyquote, - }, - ); - const expected = t.Output; - assertEquals(actual, expected); - } - }, - }); -} - -const parseTestCases = [ - { - name: "simple", - in: "a,b,c", - skipFirstRow: false, - result: [["a", "b", "c"]], - }, - { - name: "simple Bufreader", - in: new BufReader(new StringReader("a,b,c")), - skipFirstRow: false, - result: [["a", "b", "c"]], - }, - { - name: "multiline", - in: "a,b,c\ne,f,g\n", - skipFirstRow: false, - result: [ - ["a", "b", "c"], - ["e", "f", "g"], - ], - }, - { - name: "header mapping boolean", - in: "a,b,c\ne,f,g\n", - skipFirstRow: true, - result: [{ a: "e", b: "f", c: "g" }], - }, - { - name: "header mapping array", - in: "a,b,c\ne,f,g\n", - columns: ["this", "is", "sparta"], - result: [ - { this: "a", is: "b", sparta: "c" }, - { this: "e", is: "f", sparta: "g" }, - ], - }, - { - name: "header mapping object", - in: "a,b,c\ne,f,g\n", - columns: [{ name: "this" }, { name: "is" }, { name: "sparta" }], - result: [ - { this: "a", is: "b", sparta: "c" }, - { this: "e", is: "f", sparta: "g" }, - ], - }, - { - name: "header mapping parse entry", - in: "a,b,c\ne,f,g\n", - columns: [ - { - name: "this", - parse: (e: string): string => { - return `b${e}$$`; - }, - }, - { - name: "is", - parse: (e: string): number => { - return e.length; - }, - }, - { - name: "sparta", - parse: (e: string): unknown => { - return { bim: `boom-${e}` }; - }, - }, - ], - result: [ - { this: "ba$$", is: 1, sparta: { bim: `boom-c` } }, - { this: "be$$", is: 1, sparta: { bim: `boom-g` } }, - ], - }, - { - name: "multiline parse", - in: "a,b,c\ne,f,g\n", - parse: (e: string[]): unknown => { - return { super: e[0], street: e[1], fighter: e[2] }; - }, - skipFirstRow: false, - result: [ - { super: "a", street: "b", fighter: "c" }, - { super: "e", street: "f", fighter: "g" }, - ], - }, - { - name: "header mapping object parseline", - in: "a,b,c\ne,f,g\n", - columns: [{ name: "this" }, { name: "is" }, { name: "sparta" }], - parse: (e: Record<string, unknown>): unknown => { - return { super: e.this, street: e.is, fighter: e.sparta }; - }, - result: [ - { super: "a", street: "b", fighter: "c" }, - { super: "e", street: "f", fighter: "g" }, - ], - }, - { - name: "provides both opts.skipFirstRow and opts.columns", - in: "a,b,1\nc,d,2\ne,f,3", - skipFirstRow: true, - columns: [ - { name: "foo" }, - { name: "bar" }, - { name: "baz", parse: (e: string) => Number(e) }, - ], - result: [ - { foo: "c", bar: "d", baz: 2 }, - { foo: "e", bar: "f", baz: 3 }, - ], - }, -]; - -for (const testCase of parseTestCases) { - Deno.test({ - name: `[CSV] Parse ${testCase.name}`, - async fn(): Promise<void> { - const r = await parse(testCase.in, { - skipFirstRow: testCase.skipFirstRow, - columns: testCase.columns, - parse: testCase.parse as (input: unknown) => unknown, - }); - assertEquals(r, testCase.result); - }, - }); -} - -Deno.test({ - name: "[CSV] ParseError.message", - fn(): void { - assertEquals( - new ParseError(2, 2, null, ERR_FIELD_COUNT).message, - `record on line 2: ${ERR_FIELD_COUNT}`, - ); - - assertEquals( - new ParseError(1, 2, 1, ERR_QUOTE).message, - `record on line 1; parse error on line 2, column 1: ${ERR_QUOTE}`, - ); - - assertEquals( - new ParseError(1, 1, 7, ERR_QUOTE).message, - `parse error on line 1, column 7: ${ERR_QUOTE}`, - ); - }, -}); diff --git a/std/encoding/hex.ts b/std/encoding/hex.ts deleted file mode 100644 index c5cb51973..000000000 --- a/std/encoding/hex.ts +++ /dev/null @@ -1,111 +0,0 @@ -// Ported from Go -// https://github.com/golang/go/blob/go1.12.5/src/encoding/hex/hex.go -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -const hexTable = new TextEncoder().encode("0123456789abcdef"); - -/** - * ErrInvalidByte takes an invalid byte and returns an Error. - * @param byte - */ -export function errInvalidByte(byte: number): Error { - return new Error( - "encoding/hex: invalid byte: " + - new TextDecoder().decode(new Uint8Array([byte])), - ); -} - -/** ErrLength returns an error about odd string length. */ -export function errLength(): Error { - return new Error("encoding/hex: odd length hex string"); -} - -// fromHexChar converts a hex character into its value. -function fromHexChar(byte: number): number { - // '0' <= byte && byte <= '9' - if (48 <= byte && byte <= 57) return byte - 48; - // 'a' <= byte && byte <= 'f' - if (97 <= byte && byte <= 102) return byte - 97 + 10; - // 'A' <= byte && byte <= 'F' - if (65 <= byte && byte <= 70) return byte - 65 + 10; - - throw errInvalidByte(byte); -} - -/** - * EncodedLen returns the length of an encoding of n source bytes. Specifically, - * it returns n * 2. - * @param n - */ -export function encodedLen(n: number): number { - return n * 2; -} - -/** - * Encode encodes `src` into `encodedLen(src.length)` bytes. - * @param src - */ -export function encode(src: Uint8Array): Uint8Array { - const dst = new Uint8Array(encodedLen(src.length)); - for (let i = 0; i < dst.length; i++) { - const v = src[i]; - dst[i * 2] = hexTable[v >> 4]; - dst[i * 2 + 1] = hexTable[v & 0x0f]; - } - return dst; -} - -/** - * EncodeToString returns the hexadecimal encoding of `src`. - * @param src - */ -export function encodeToString(src: Uint8Array): string { - return new TextDecoder().decode(encode(src)); -} - -/** - * Decode decodes `src` into `decodedLen(src.length)` bytes - * If the input is malformed an error will be thrown - * the error. - * @param src - */ -export function decode(src: Uint8Array): Uint8Array { - const dst = new Uint8Array(decodedLen(src.length)); - for (let i = 0; i < dst.length; i++) { - const a = fromHexChar(src[i * 2]); - const b = fromHexChar(src[i * 2 + 1]); - dst[i] = (a << 4) | b; - } - - if (src.length % 2 == 1) { - // Check for invalid char before reporting bad length, - // since the invalid char (if present) is an earlier problem. - fromHexChar(src[dst.length * 2]); - throw errLength(); - } - - return dst; -} - -/** - * DecodedLen returns the length of decoding `x` source bytes. - * Specifically, it returns `x / 2`. - * @param x - */ -export function decodedLen(x: number): number { - return x >>> 1; -} - -/** - * DecodeString returns the bytes represented by the hexadecimal string `s`. - * DecodeString expects that src contains only hexadecimal characters and that - * src has even length. - * If the input is malformed, DecodeString will throw an error. - * @param s the `string` to decode to `Uint8Array` - */ -export function decodeString(s: string): Uint8Array { - return decode(new TextEncoder().encode(s)); -} diff --git a/std/encoding/hex_test.ts b/std/encoding/hex_test.ts deleted file mode 100644 index 53161a3ba..000000000 --- a/std/encoding/hex_test.ts +++ /dev/null @@ -1,154 +0,0 @@ -// Ported from Go -// https://github.com/golang/go/blob/go1.12.5/src/encoding/hex/hex.go -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assertEquals, assertThrows } from "../testing/asserts.ts"; - -import { - decode, - decodedLen, - decodeString, - encode, - encodedLen, - encodeToString, - errInvalidByte, - errLength, -} from "./hex.ts"; - -function toByte(s: string): number { - return new TextEncoder().encode(s)[0]; -} - -const testCases = [ - // encoded(hex) / decoded(Uint8Array) - ["", []], - ["0001020304050607", [0, 1, 2, 3, 4, 5, 6, 7]], - ["08090a0b0c0d0e0f", [8, 9, 10, 11, 12, 13, 14, 15]], - ["f0f1f2f3f4f5f6f7", [0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7]], - ["f8f9fafbfcfdfeff", [0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff]], - ["67", Array.from(new TextEncoder().encode("g"))], - ["e3a1", [0xe3, 0xa1]], -]; - -const errCases = [ - // encoded(hex) / error - ["0", errLength()], - ["zd4aa", errInvalidByte(toByte("z"))], - ["d4aaz", errInvalidByte(toByte("z"))], - ["30313", errLength()], - ["0g", errInvalidByte(new TextEncoder().encode("g")[0])], - ["00gg", errInvalidByte(new TextEncoder().encode("g")[0])], - ["0\x01", errInvalidByte(new TextEncoder().encode("\x01")[0])], - ["ffeed", errLength()], -]; - -Deno.test({ - name: "[encoding.hex] encodedLen", - fn(): void { - assertEquals(encodedLen(0), 0); - assertEquals(encodedLen(1), 2); - assertEquals(encodedLen(2), 4); - assertEquals(encodedLen(3), 6); - assertEquals(encodedLen(4), 8); - }, -}); - -Deno.test({ - name: "[encoding.hex] encode", - fn(): void { - { - const srcStr = "abc"; - const src = new TextEncoder().encode(srcStr); - const dest = encode(src); - assertEquals(src, new Uint8Array([97, 98, 99])); - assertEquals(dest.length, 6); - } - - for (const [enc, dec] of testCases) { - const src = new Uint8Array(dec as number[]); - const dest = encode(src); - assertEquals(dest.length, src.length * 2); - assertEquals(new TextDecoder().decode(dest), enc); - } - }, -}); - -Deno.test({ - name: "[encoding.hex] encodeToString", - fn(): void { - for (const [enc, dec] of testCases) { - assertEquals(encodeToString(new Uint8Array(dec as number[])), enc); - } - }, -}); - -Deno.test({ - name: "[encoding.hex] decodedLen", - fn(): void { - assertEquals(decodedLen(0), 0); - assertEquals(decodedLen(2), 1); - assertEquals(decodedLen(4), 2); - assertEquals(decodedLen(6), 3); - assertEquals(decodedLen(8), 4); - }, -}); - -Deno.test({ - name: "[encoding.hex] decode", - fn(): void { - // Case for decoding uppercase hex characters, since - // Encode always uses lowercase. - const extraTestcase = [ - ["F8F9FAFBFCFDFEFF", [0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff]], - ]; - - const cases = testCases.concat(extraTestcase); - - for (const [enc, dec] of cases) { - const src = new TextEncoder().encode(enc as string); - const dest = decode(src); - assertEquals(Array.from(dest), Array.from(dec as number[])); - } - }, -}); - -Deno.test({ - name: "[encoding.hex] decodeString", - fn(): void { - for (const [enc, dec] of testCases) { - const dst = decodeString(enc as string); - - assertEquals(dec, Array.from(dst)); - } - }, -}); - -Deno.test({ - name: "[encoding.hex] decode error", - fn(): void { - for (const [input, expectedErr] of errCases) { - assertThrows( - () => decode(new TextEncoder().encode(input as string)), - Error, - (expectedErr as Error).message, - ); - } - }, -}); - -Deno.test({ - name: "[encoding.hex] decodeString error", - fn(): void { - for (const [input, expectedErr] of errCases) { - assertThrows( - (): void => { - decodeString(input as string); - }, - Error, - (expectedErr as Error).message, - ); - } - }, -}); diff --git a/std/encoding/testdata/CRLF.toml b/std/encoding/testdata/CRLF.toml deleted file mode 100644 index 92264888a..000000000 --- a/std/encoding/testdata/CRLF.toml +++ /dev/null @@ -1,3 +0,0 @@ -[boolean] -bool1 = true -bool2 = false
\ No newline at end of file diff --git a/std/encoding/testdata/arrayTable.toml b/std/encoding/testdata/arrayTable.toml deleted file mode 100644 index 3788b7e7c..000000000 --- a/std/encoding/testdata/arrayTable.toml +++ /dev/null @@ -1,12 +0,0 @@ - -[[bin]] -name = "deno" -path = "cli/main.rs" - -[[bin]] -name = "deno_core" -path = "src/foo.rs" - -[[nib]] -name = "node" -path = "not_found"
\ No newline at end of file diff --git a/std/encoding/testdata/arrays.toml b/std/encoding/testdata/arrays.toml deleted file mode 100644 index f52509bf2..000000000 --- a/std/encoding/testdata/arrays.toml +++ /dev/null @@ -1,8 +0,0 @@ -[arrays] -data = [ ["gamma", "delta"], [1, 2] ] # comment after an array caused issue #7072 - -# Line breaks are OK when inside arrays -hosts = [ - "alpha", - "omega" -] # comment
\ No newline at end of file diff --git a/std/encoding/testdata/boolean.toml b/std/encoding/testdata/boolean.toml deleted file mode 100644 index e3e287981..000000000 --- a/std/encoding/testdata/boolean.toml +++ /dev/null @@ -1,4 +0,0 @@ -[boolean] # i hate comments -bool1 = true -bool2 = false -bool3 = true # I love comments
\ No newline at end of file diff --git a/std/encoding/testdata/cargo.toml b/std/encoding/testdata/cargo.toml deleted file mode 100644 index cb0c85fe6..000000000 --- a/std/encoding/testdata/cargo.toml +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -# Dummy package info required by `cargo fetch`. - -[workspace] -members = [ - "./", - "core", -] - -[[bin]] -name = "deno" -path = "cli/main.rs" - -[package] -name = "deno" -version = "0.3.4" -edition = "2018" - -[dependencies] -deno_core = { path = "./core" } - -atty = "0.2.11" -dirs = "1.0.5" -flatbuffers = "0.5.0" -futures = "0.1.25" -getopts = "0.2.18" -http = "0.1.16" -hyper = "0.12.24" -hyper-rustls = "0.16.0" -integer-atomics = "1.0.2" -lazy_static = "1.3.0" -libc = "0.2.49" -log = "0.4.6" -rand = "0.6.5" -regex = "1.1.0" -remove_dir_all = "0.5.2" -ring = "0.14.6" -rustyline = "3.0.0" -serde_json = "1.0.38" -source-map-mappings = "0.5.0" -tempfile = "3.0.7" -tokio = "0.1.15" -tokio-executor = "0.1.6" -tokio-fs = "0.1.5" -tokio-io = "0.1.11" -tokio-process = "0.2.3" -tokio-threadpool = "0.1.11" -url = "1.7.2" - -[target.'cfg(windows)'.dependencies] -winapi = "0.3.6" diff --git a/std/encoding/testdata/cargoTest.toml b/std/encoding/testdata/cargoTest.toml deleted file mode 100644 index 47e7f6e4d..000000000 --- a/std/encoding/testdata/cargoTest.toml +++ /dev/null @@ -1,147 +0,0 @@ -# This is a TOML document. - -title = "TOML Example" - -[deeply.nested.object.in.the.toml] -name = "Tom Preston-Werner" -dob = 2009-05-27T07:32:00 - -[database] -server = "192.168.1.1" -ports = [ 8001, 8001, 8002 ] -connection_max = 5000 -enabled = true - -[servers] - - # Indentation (tabs and/or spaces) is allowed but not required - [servers.alpha] - ip = "10.0.0.1" - dc = "eqdc10" - - [servers.beta] - ip = "10.0.0.2" - dc = "eqdc10" - -[clients] -data = [ ["gamma", "delta"], [1, 2] ] - -# Line breaks are OK when inside arrays -hosts = [ - "alpha", - "omega" -] - -[strings] -str0 = "deno" -str1 = """ -Roses are red - Violets are blue""" -# On a Unix system, the above multi-line string will most likely be the same as: -str2 = "Roses are red\nViolets are blue" - -# On a Windows system, it will most likely be equivalent to: -str3 = "Roses are red\r\nViolets are blue" -str4 = "The quick brown fox jumps over the lazy dog." -str5 = "this is a \"quote\"" - -str5 = """ -The quick brown \ - - - fox jumps over \ - the lazy dog.""" - -str6 = """\ - The quick brown \ - fox jumps over \ - the lazy dog.\ - """ -lines = ''' -The first newline is -trimmed in raw strings. - All other whitespace - is preserved. -''' - -[Integer] -int1 = +99 -int2 = 42 -int3 = 0 -int4 = -17 -int5 = 1_000 -int6 = 5_349_221 -int7 = 1_2_3_4_5 # VALID but discouraged - -# hexadecimal with prefix `0x` -hex1 = 0xDEADBEEF -hex2 = 0xdeadbeef -hex3 = 0xdead_beef - -# octal with prefix `0o` -oct1 = 0o01234567 -oct2 = 0o755 # useful for Unix file permissions - -# binary with prefix `0b` -bin1 = 0b11010110 - -[Date-Time] -odt1 = 1979-05-27T07:32:00Z -odt2 = 1979-05-27T00:32:00-07:00 -odt3 = 1979-05-27T00:32:00.999999-07:00 -odt4 = 1979-05-27 07:32:00Z -ld1 = 1979-05-27 -lt1 = 07:32:00 #buggy -lt2 = 00:32:00.999999 #buggy - -[boolean] -bool1 = true -bool2 = false - -[float] -# fractional -flt1 = +1.0 -flt2 = 3.1415 -flt3 = -0.01 - -# exponent -flt4 = 5e+22 -flt5 = 1e6 -flt6 = -2E-2 - -# both -flt7 = 6.626e-34 -flt8 = 224_617.445_991_228 -# infinity -sf1 = inf # positive infinity -sf2 = +inf # positive infinity -sf3 = -inf # negative infinity - -# not a number -sf4 = nan # actual sNaN/qNaN encoding is implementation specific -sf5 = +nan # same as `nan` -sf6 = -nan # valid, actual encoding is implementation specific - -[Table] -name = { first = "Tom", last = "Preston-Werner" } -point = { x = 1, y = 2 } -animal = { type.name = "pug" } - -[[fruit]] - name = "apple" - - [fruit.physical] - color = "red" - shape = "round" - - [[fruit.variety]] - name = "red delicious" - - [[fruit.variety]] - name = "granny smith" - -[[fruit]] - name = "banana" - - [[fruit.variety]] - name = "plantain" diff --git a/std/encoding/testdata/comment.toml b/std/encoding/testdata/comment.toml deleted file mode 100644 index 6bc9be045..000000000 --- a/std/encoding/testdata/comment.toml +++ /dev/null @@ -1,29 +0,0 @@ -# This is a full-line comment -str0 = 'value' # This is a comment at the end of a line -str1 = "# This is not a comment" # but this is -str2 = """ # this is not a comment! -A multiline string with a # -# this is also not a comment -""" # this is definitely a comment - -str3 = ''' -"# not a comment" - # this is a real tab on purpose -# not a comment -''' # comment - -point0 = { x = 1, y = 2, str0 = "#not a comment", z = 3 } # comment -point1 = { x = 7, y = 8, z = 9, str0 = "#not a comment"} # comment - -[deno] # this comment is fine -features = ["#secure by default", "supports typescript # not a comment"] # Comment caused Issue #7072 -url = "https://deno.land/" # comment -is_not_node = true # comment - -[toml] # Comment caused Issue #7072 (case 2) -name = "Tom's Obvious, Minimal Language" -objectives = [ # Comment - "easy to read", # Comment - "minimal config file", - "#not a comment" # comment -] # comment diff --git a/std/encoding/testdata/datetime.toml b/std/encoding/testdata/datetime.toml deleted file mode 100644 index 62377a4ba..000000000 --- a/std/encoding/testdata/datetime.toml +++ /dev/null @@ -1,8 +0,0 @@ -[datetime] -odt1 = 1979-05-27T07:32:00Z # Comment -odt2 = 1979-05-27T00:32:00-07:00 # Comment -odt3 = 1979-05-27T00:32:00.999999-07:00 # Comment -odt4 = 1979-05-27 07:32:00Z # Comment -ld1 = 1979-05-27 # Comment -lt1 = 07:32:00 # Comment -lt2 = 00:32:00.999999 # Comment diff --git a/std/encoding/testdata/float.toml b/std/encoding/testdata/float.toml deleted file mode 100644 index 6a384179c..000000000 --- a/std/encoding/testdata/float.toml +++ /dev/null @@ -1,23 +0,0 @@ -[float] -# fractional -flt1 = +1.0 # Comment -flt2 = 3.1415 # Comment -flt3 = -0.01 # Comment - -# exponent -flt4 = 5e+22 # Comment -flt5 = 1e6 # Comment -flt6 = -2E-2 # Comment - -# both -flt7 = 6.626e-34 # Comment -flt8 = 224_617.445_991_228 # Comment -# infinity -sf1 = inf # positive infinity -sf2 = +inf # positive infinity -sf3 = -inf # negative infinity - -# not a number -sf4 = nan # actual sNaN/qNaN encoding is implementation specific -sf5 = +nan # same as `nan` -sf6 = -nan # valid, actual encoding is implementation specific
\ No newline at end of file diff --git a/std/encoding/testdata/inlineArrayOfInlineTable.toml b/std/encoding/testdata/inlineArrayOfInlineTable.toml deleted file mode 100644 index a440ff927..000000000 --- a/std/encoding/testdata/inlineArrayOfInlineTable.toml +++ /dev/null @@ -1,8 +0,0 @@ -[inlineArray] -string = [ {var = "a string"} ] - -my_points = [ { x = 1, y = 2, z = 3 }, { x = 7, y = 8, z = 9 }, { x = 2, y = 4, z = 8 } ] - -points = [ { x = 1, y = 2, z = 3 }, - { x = 7, y = 8, z = 9 }, - { x = 2, y = 4, z = 8 } ]
\ No newline at end of file diff --git a/std/encoding/testdata/inlineTable.toml b/std/encoding/testdata/inlineTable.toml deleted file mode 100644 index 203cb16db..000000000 --- a/std/encoding/testdata/inlineTable.toml +++ /dev/null @@ -1,7 +0,0 @@ -[inlinetable] -name = { first = "Tom", last = "Preston-Werner" } -point = { x = 1, y = 2 } -dog = { type = { name = "pug" } } -animal.as.leaders = "tosin" -"tosin.abasi" = "guitarist" -nile = { derek.roddy = "drummer", also = { malevolant.creation = { drum.kit = "Tama" } } }
\ No newline at end of file diff --git a/std/encoding/testdata/integer.toml b/std/encoding/testdata/integer.toml deleted file mode 100644 index 3bd781e8f..000000000 --- a/std/encoding/testdata/integer.toml +++ /dev/null @@ -1,20 +0,0 @@ -[integer] -int1 = +99 -int2 = 42 -int3 = 0 -int4 = -17 -int5 = 1_000 -int6 = 5_349_221 -int7 = 1_2_3_4_5 # VALID but discouraged - -# hexadecimal with prefix `0x` -hex1 = 0xDEADBEEF -hex2 = 0xdeadbeef -hex3 = 0xdead_beef - -# octal with prefix `0o` -oct1 = 0o01234567 -oct2 = 0o755 # useful for Unix file permissions - -# binary with prefix `0b` -bin1 = 0b11010110
\ No newline at end of file diff --git a/std/encoding/testdata/simple.toml b/std/encoding/testdata/simple.toml deleted file mode 100644 index f3f6c1036..000000000 --- a/std/encoding/testdata/simple.toml +++ /dev/null @@ -1,5 +0,0 @@ -deno = "is" -not = "[node]" -regex = '<\i\c*\s*>' -NANI = '何?!' -comment = "Comment inside # the comment" # Comment diff --git a/std/encoding/testdata/string.toml b/std/encoding/testdata/string.toml deleted file mode 100644 index 640717d0e..000000000 --- a/std/encoding/testdata/string.toml +++ /dev/null @@ -1,36 +0,0 @@ -[strings] -str0 = "deno" -str1 = """ -Roses are not Deno - Violets are not Deno either""" -# On a Unix system, the above multi-line string will most likely be the same as: -str2 = "Roses are not Deno\nViolets are not Deno either" - -# On a Windows system, it will most likely be equivalent to: -str3 = "Roses are not Deno\r\nViolets are not Deno either" -str4 = "this is a \"quote\"" - -str5 = """ -The quick brown \ - - - fox jumps over \ - the lazy dog.""" - -str6 = """\ - The quick brown \ - fox jumps over \ - the lazy dog.\ - """ -lines = ''' -The first newline is -trimmed in raw strings. - All other whitespace - is preserved. -''' - -withApostrophe = "What if it's not?" -withSemicolon = "const message = 'hello world';" -withHexNumberLiteral = "Prevent bug from stripping string here ->0xabcdef" -withUnicodeChar1 = "\u3042" -withUnicodeChar2 = "Deno\U01F995" diff --git a/std/encoding/testdata/table.toml b/std/encoding/testdata/table.toml deleted file mode 100644 index 7008e6fb0..000000000 --- a/std/encoding/testdata/table.toml +++ /dev/null @@ -1,13 +0,0 @@ -[deeply.nested.object.in.the.toml] -name = "Tom Preston-Werner" - -[servers] - - # Indentation (tabs and/or spaces) is allowed but not required - [servers.alpha] - ip = "10.0.0.1" - dc = "eqdc10" - - [servers.beta] - ip = "10.0.0.2" - dc = "eqdc20"
\ No newline at end of file diff --git a/std/encoding/toml.ts b/std/encoding/toml.ts deleted file mode 100644 index 6cd8faa71..000000000 --- a/std/encoding/toml.ts +++ /dev/null @@ -1,736 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { deepAssign } from "../_util/deep_assign.ts"; -import { assert } from "../_util/assert.ts"; - -class TOMLError extends Error {} - -class KeyValuePair { - constructor(public key: string, public value: unknown) {} -} - -class ParserGroup { - arrValues: unknown[] = []; - objValues: Record<string, unknown> = {}; - - constructor(public type: string, public name: string) {} -} - -class ParserContext { - currentGroup?: ParserGroup; - output: Record<string, unknown> = {}; -} - -class Parser { - tomlLines: string[]; - context: ParserContext; - constructor(tomlString: string) { - this.tomlLines = this._split(tomlString); - this.context = new ParserContext(); - } - _sanitize(): void { - const out: string[] = []; - for (let i = 0; i < this.tomlLines.length; i++) { - const s = this.tomlLines[i]; - const trimmed = s.trim(); - if (trimmed !== "") { - out.push(s); - } - } - this.tomlLines = out; - this._removeComments(); - this._mergeMultilines(); - } - - _removeComments(): void { - function isFullLineComment(line: string) { - return line.match(/^#/) ? true : false; - } - - function stringStart(line: string) { - const m = line.match(/(?:=\s*\[?\s*)("""|'''|"|')/); - if (!m) { - return false; - } - - // We want to know which syntax was used to open the string - openStringSyntax = m[1]; - return true; - } - - function stringEnd(line: string) { - // match the syntax used to open the string when searching for string close - // e.g. if we open with ''' we must close with a ''' - const reg = RegExp(`(?<!(=\\s*))${openStringSyntax}(?!(.*"))`); - if (!line.match(reg)) { - return false; - } - - openStringSyntax = ""; - return true; - } - - const cleaned = []; - let isOpenString = false; - let openStringSyntax = ""; - for (let i = 0; i < this.tomlLines.length; i++) { - const line = this.tomlLines[i]; - - // stringStart and stringEnd are separate conditions to - // support both single-line and multi-line strings - if (!isOpenString && stringStart(line)) { - isOpenString = true; - } - if (isOpenString && stringEnd(line)) { - isOpenString = false; - } - - if (!isOpenString && !isFullLineComment(line)) { - const out = line.split( - /(?<=([\,\[\]\{\}]|".*"|'.*'|\w(?!.*("|')+))\s*)#/gi, - ); - cleaned.push(out[0].trim()); - } else if (isOpenString || !isFullLineComment(line)) { - cleaned.push(line); - } - - // If a single line comment doesnt end on the same line, throw error - if ( - isOpenString && (openStringSyntax === "'" || openStringSyntax === '"') - ) { - throw new TOMLError(`Single-line string is not closed:\n${line}`); - } - } - - if (isOpenString) { - throw new TOMLError(`Incomplete string until EOF`); - } - - this.tomlLines = cleaned; - } - - _mergeMultilines(): void { - function arrayStart(line: string): boolean { - const reg = /.*=\s*\[/g; - return reg.test(line) && !(line[line.length - 1] === "]"); - } - - function arrayEnd(line: string): boolean { - return line[line.length - 1] === "]"; - } - - function stringStart(line: string): boolean { - const m = line.match(/.*=\s*(?:\"\"\"|''')/); - if (!m) { - return false; - } - return !line.endsWith(`"""`) || !line.endsWith(`'''`); - } - - function stringEnd(line: string): boolean { - return line.endsWith(`'''`) || line.endsWith(`"""`); - } - - function isLiteralString(line: string): boolean { - return line.match(/'''/) ? true : false; - } - - const merged = []; - let acc = [], - isLiteral = false, - capture = false, - captureType = "", - merge = false; - - for (let i = 0; i < this.tomlLines.length; i++) { - const line = this.tomlLines[i]; - const trimmed = line.trim(); - if (!capture && arrayStart(trimmed)) { - capture = true; - captureType = "array"; - } else if (!capture && stringStart(trimmed)) { - isLiteral = isLiteralString(trimmed); - capture = true; - captureType = "string"; - } else if (capture && arrayEnd(trimmed)) { - merge = true; - } else if (capture && stringEnd(trimmed)) { - merge = true; - } - - if (capture) { - if (isLiteral) { - acc.push(line); - } else { - acc.push(trimmed); - } - } else { - if (isLiteral) { - merged.push(line); - } else { - merged.push(trimmed); - } - } - - if (merge) { - capture = false; - merge = false; - if (captureType === "string") { - merged.push( - acc - .join("\n") - .replace(/"""/g, '"') - .replace(/'''/g, `'`) - .replace(/\n/g, "\\n"), - ); - isLiteral = false; - } else { - merged.push(acc.join("")); - } - captureType = ""; - acc = []; - } - } - this.tomlLines = merged; - } - _unflat( - keys: string[], - values: Record<string, unknown> | unknown[] = {}, - cObj: Record<string, unknown> | unknown[] = {}, - ): Record<string, unknown> { - const out: Record<string, unknown> = {}; - if (keys.length === 0) { - return cObj as Record<string, unknown>; - } else { - if (Object.keys(cObj).length === 0) { - cObj = values; - } - const key: string | undefined = keys.pop(); - if (key) { - out[key] = cObj; - } - return this._unflat(keys, values, out); - } - } - _groupToOutput(): void { - assert(this.context.currentGroup != null, "currentGroup must be set"); - const arrProperty = this.context.currentGroup.name - .replace(/"/g, "") - .replace(/'/g, "") - .split("."); - let u = {}; - if (this.context.currentGroup.type === "array") { - u = this._unflat(arrProperty, this.context.currentGroup.arrValues); - } else { - u = this._unflat(arrProperty, this.context.currentGroup.objValues); - } - deepAssign(this.context.output, u); - delete this.context.currentGroup; - } - _split(str: string): string[] { - const out = []; - out.push(...str.split("\n")); - return out; - } - _isGroup(line: string): boolean { - const t = line.trim(); - return t[0] === "[" && /\[(.*)\]/.exec(t) ? true : false; - } - _isDeclaration(line: string): boolean { - return line.split("=").length > 1; - } - _createGroup(line: string): void { - const captureReg = /\[(.*)\]/; - if (this.context.currentGroup) { - this._groupToOutput(); - } - - let type; - let m = line.match(captureReg); - assert(m != null, "line mut be matched"); - let name = m[1]; - if (name.match(/\[.*\]/)) { - type = "array"; - m = name.match(captureReg); - assert(m != null, "name must be matched"); - name = m[1]; - } else { - type = "object"; - } - this.context.currentGroup = new ParserGroup(type, name); - } - _processDeclaration(line: string): KeyValuePair { - const idx = line.indexOf("="); - const key = line.substring(0, idx).trim(); - const value = this._parseData(line.slice(idx + 1)); - return new KeyValuePair(key, value); - } - _parseData(dataString: string): unknown { - dataString = dataString.trim(); - switch (dataString[0]) { - case '"': - case "'": - return this._parseString(dataString); - case "[": - case "{": - return this._parseInlineTableOrArray(dataString); - default: { - // Strip a comment. - const match = /#.*$/.exec(dataString); - if (match) { - dataString = dataString.slice(0, match.index).trim(); - } - - switch (dataString) { - case "true": - return true; - case "false": - return false; - case "inf": - case "+inf": - return Infinity; - case "-inf": - return -Infinity; - case "nan": - case "+nan": - case "-nan": - return NaN; - default: - return this._parseNumberOrDate(dataString); - } - } - } - } - _parseInlineTableOrArray(dataString: string): unknown { - const invalidArr = /,\]/g.exec(dataString); - if (invalidArr) { - dataString = dataString.replace(/,]/g, "]"); - } - - if ( - (dataString[0] === "{" && dataString[dataString.length - 1] === "}") || - (dataString[0] === "[" && dataString[dataString.length - 1] === "]") - ) { - const reg = /([a-zA-Z0-9-_\.]*) (=)/gi; - let result; - while ((result = reg.exec(dataString))) { - const ogVal = result[0]; - const newVal = ogVal - .replace(result[1], `"${result[1]}"`) - .replace(result[2], ":"); - dataString = dataString.replace(ogVal, newVal); - } - return JSON.parse(dataString); - } - throw new TOMLError("Malformed inline table or array literal"); - } - _parseString(dataString: string): string { - const quote = dataString[0]; - // Handle First and last EOL for multiline strings - if (dataString.startsWith(`"\\n`)) { - dataString = dataString.replace(`"\\n`, `"`); - } else if (dataString.startsWith(`'\\n`)) { - dataString = dataString.replace(`'\\n`, `'`); - } - if (dataString.endsWith(`\\n"`)) { - dataString = dataString.replace(`\\n"`, `"`); - } else if (dataString.endsWith(`\\n'`)) { - dataString = dataString.replace(`\\n'`, `'`); - } - let value = ""; - for (let i = 1; i < dataString.length; i++) { - switch (dataString[i]) { - case "\\": - i++; - // See https://toml.io/en/v1.0.0-rc.3#string - switch (dataString[i]) { - case "b": - value += "\b"; - break; - case "t": - value += "\t"; - break; - case "n": - value += "\n"; - break; - case "f": - value += "\f"; - break; - case "r": - value += "\r"; - break; - case "u": - case "U": { - // Unicode character - const codePointLen = dataString[i] === "u" ? 4 : 6; - const codePoint = parseInt( - "0x" + dataString.slice(i + 1, i + 1 + codePointLen), - 16, - ); - value += String.fromCodePoint(codePoint); - i += codePointLen; - break; - } - case "\\": - value += "\\"; - break; - default: - value += dataString[i]; - break; - } - break; - case quote: - if (dataString[i - 1] !== "\\") { - return value; - } - break; - default: - value += dataString[i]; - break; - } - } - throw new TOMLError("Incomplete string literal"); - } - _parseNumberOrDate(dataString: string): unknown { - if (this._isDate(dataString)) { - return new Date(dataString); - } - - if (this._isLocalTime(dataString)) { - return dataString; - } - - // If binary / octal / hex - const hex = /^(0(?:x|o|b)[0-9a-f_]*)/gi.exec(dataString); - if (hex && hex[0]) { - return hex[0].trim(); - } - - const testNumber = this._isParsableNumber(dataString); - if (testNumber !== false && !isNaN(testNumber as number)) { - return testNumber; - } - - return String(dataString); - } - _isLocalTime(str: string): boolean { - const reg = /(\d{2}):(\d{2}):(\d{2})/; - return reg.test(str); - } - _isParsableNumber(dataString: string): number | boolean { - const m = /((?:\+|-|)[0-9_\.e+\-]*)[^#]/i.exec(dataString); - if (!m) { - return false; - } else { - return parseFloat(m[0].replace(/_/g, "")); - } - } - _isDate(dateStr: string): boolean { - const reg = /\d{4}-\d{2}-\d{2}/; - return reg.test(dateStr); - } - _parseDeclarationName(declaration: string): string[] { - const out = []; - let acc = []; - let inLiteral = false; - for (let i = 0; i < declaration.length; i++) { - const c = declaration[i]; - switch (c) { - case ".": - if (!inLiteral) { - out.push(acc.join("")); - acc = []; - } else { - acc.push(c); - } - break; - case `"`: - if (inLiteral) { - inLiteral = false; - } else { - inLiteral = true; - } - break; - default: - acc.push(c); - break; - } - } - if (acc.length !== 0) { - out.push(acc.join("")); - } - return out; - } - _parseLines(): void { - for (let i = 0; i < this.tomlLines.length; i++) { - const line = this.tomlLines[i]; - - // TODO(zekth): Handle unflat of array of tables - if (this._isGroup(line)) { - // if the current group is an array we push the - // parsed objects in it. - if ( - this.context.currentGroup && - this.context.currentGroup.type === "array" - ) { - this.context.currentGroup.arrValues.push( - this.context.currentGroup.objValues, - ); - this.context.currentGroup.objValues = {}; - } - // If we need to create a group or to change group - if ( - !this.context.currentGroup || - (this.context.currentGroup && - this.context.currentGroup.name !== - line.replace(/\[/g, "").replace(/\]/g, "")) - ) { - this._createGroup(line); - continue; - } - } - if (this._isDeclaration(line)) { - const kv = this._processDeclaration(line); - const key = kv.key; - const value = kv.value; - if (!this.context.currentGroup) { - this.context.output[key] = value; - } else { - this.context.currentGroup.objValues[key] = value; - } - } - } - if (this.context.currentGroup) { - if (this.context.currentGroup.type === "array") { - this.context.currentGroup.arrValues.push( - this.context.currentGroup.objValues, - ); - } - this._groupToOutput(); - } - } - _cleanOutput(): void { - this._propertyClean(this.context.output); - } - _propertyClean(obj: Record<string, unknown>): void { - const keys = Object.keys(obj); - for (let i = 0; i < keys.length; i++) { - let k = keys[i]; - if (k) { - let v = obj[k]; - const pathDeclaration = this._parseDeclarationName(k); - delete obj[k]; - if (pathDeclaration.length > 1) { - const shift = pathDeclaration.shift(); - if (shift) { - k = shift.replace(/"/g, ""); - v = this._unflat(pathDeclaration, v as Record<string, unknown>); - } - } else { - k = k.replace(/"/g, ""); - } - obj[k] = v; - if (v instanceof Object) { - // deno-lint-ignore no-explicit-any - this._propertyClean(v as any); - } - } - } - } - parse(): Record<string, unknown> { - this._sanitize(); - this._parseLines(); - this._cleanOutput(); - return this.context.output; - } -} - -// Bare keys may only contain ASCII letters, -// ASCII digits, underscores, and dashes (A-Za-z0-9_-). -function joinKeys(keys: string[]): string { - // Dotted keys are a sequence of bare or quoted keys joined with a dot. - // This allows for grouping similar properties together: - return keys - .map((str: string): string => { - return str.match(/[^A-Za-z0-9_-]/) ? `"${str}"` : str; - }) - .join("."); -} - -class Dumper { - maxPad = 0; - srcObject: Record<string, unknown>; - output: string[] = []; - constructor(srcObjc: Record<string, unknown>) { - this.srcObject = srcObjc; - } - dump(): string[] { - // deno-lint-ignore no-explicit-any - this.output = this._parse(this.srcObject as any); - this.output = this._format(); - return this.output; - } - _parse(obj: Record<string, unknown>, keys: string[] = []): string[] { - const out = []; - const props = Object.keys(obj); - const propObj = props.filter((e: string): boolean => { - if (obj[e] instanceof Array) { - const d: unknown[] = obj[e] as unknown[]; - return !this._isSimplySerializable(d[0]); - } - return !this._isSimplySerializable(obj[e]); - }); - const propPrim = props.filter((e: string): boolean => { - if (obj[e] instanceof Array) { - const d: unknown[] = obj[e] as unknown[]; - return this._isSimplySerializable(d[0]); - } - return this._isSimplySerializable(obj[e]); - }); - const k = propPrim.concat(propObj); - for (let i = 0; i < k.length; i++) { - const prop = k[i]; - const value = obj[prop]; - if (value instanceof Date) { - out.push(this._dateDeclaration([prop], value)); - } else if (typeof value === "string" || value instanceof RegExp) { - out.push(this._strDeclaration([prop], value.toString())); - } else if (typeof value === "number") { - out.push(this._numberDeclaration([prop], value)); - } else if (typeof value === "boolean") { - out.push(this._boolDeclaration([prop], value)); - } else if ( - value instanceof Array && - this._isSimplySerializable(value[0]) - ) { - // only if primitives types in the array - out.push(this._arrayDeclaration([prop], value)); - } else if ( - value instanceof Array && - !this._isSimplySerializable(value[0]) - ) { - // array of objects - for (let i = 0; i < value.length; i++) { - out.push(""); - out.push(this._headerGroup([...keys, prop])); - out.push(...this._parse(value[i], [...keys, prop])); - } - } else if (typeof value === "object") { - out.push(""); - out.push(this._header([...keys, prop])); - if (value) { - const toParse = value as Record<string, unknown>; - out.push(...this._parse(toParse, [...keys, prop])); - } - // out.push(...this._parse(value, `${path}${prop}.`)); - } - } - out.push(""); - return out; - } - _isSimplySerializable(value: unknown): boolean { - return ( - typeof value === "string" || - typeof value === "number" || - typeof value === "boolean" || - value instanceof RegExp || - value instanceof Date || - value instanceof Array - ); - } - _header(keys: string[]): string { - return `[${joinKeys(keys)}]`; - } - _headerGroup(keys: string[]): string { - return `[[${joinKeys(keys)}]]`; - } - _declaration(keys: string[]): string { - const title = joinKeys(keys); - if (title.length > this.maxPad) { - this.maxPad = title.length; - } - return `${title} = `; - } - _arrayDeclaration(keys: string[], value: unknown[]): string { - return `${this._declaration(keys)}${JSON.stringify(value)}`; - } - _strDeclaration(keys: string[], value: string): string { - return `${this._declaration(keys)}"${value}"`; - } - _numberDeclaration(keys: string[], value: number): string { - switch (value) { - case Infinity: - return `${this._declaration(keys)}inf`; - case -Infinity: - return `${this._declaration(keys)}-inf`; - default: - return `${this._declaration(keys)}${value}`; - } - } - _boolDeclaration(keys: string[], value: boolean): string { - return `${this._declaration(keys)}${value}`; - } - _dateDeclaration(keys: string[], value: Date): string { - function dtPad(v: string, lPad = 2): string { - return v.padStart(lPad, "0"); - } - const m = dtPad((value.getUTCMonth() + 1).toString()); - const d = dtPad(value.getUTCDate().toString()); - const h = dtPad(value.getUTCHours().toString()); - const min = dtPad(value.getUTCMinutes().toString()); - const s = dtPad(value.getUTCSeconds().toString()); - const ms = dtPad(value.getUTCMilliseconds().toString(), 3); - // formatted date - const fData = `${value.getUTCFullYear()}-${m}-${d}T${h}:${min}:${s}.${ms}`; - return `${this._declaration(keys)}${fData}`; - } - _format(): string[] { - const rDeclaration = /(.*)\s=/; - const out = []; - for (let i = 0; i < this.output.length; i++) { - const l = this.output[i]; - // we keep empty entry for array of objects - if (l[0] === "[" && l[1] !== "[") { - // empty object - if (this.output[i + 1] === "") { - i += 1; - continue; - } - out.push(l); - } else { - const m = rDeclaration.exec(l); - if (m) { - out.push(l.replace(m[1], m[1].padEnd(this.maxPad))); - } else { - out.push(l); - } - } - } - // Cleaning multiple spaces - const cleanedOutput = []; - for (let i = 0; i < out.length; i++) { - const l = out[i]; - if (!(l === "" && out[i + 1] === "")) { - cleanedOutput.push(l); - } - } - return cleanedOutput; - } -} - -/** - * Stringify dumps source object into TOML string and returns it. - * @param srcObj - */ -export function stringify(srcObj: Record<string, unknown>): string { - return new Dumper(srcObj).dump().join("\n"); -} - -/** - * Parse parses TOML string into an object. - * @param tomlString - */ -export function parse(tomlString: string): Record<string, unknown> { - // File is potentially using EOL CRLF - tomlString = tomlString.replace(/\r\n/g, "\n").replace(/\\\n/g, "\n"); - return new Parser(tomlString).parse(); -} diff --git a/std/encoding/toml_test.ts b/std/encoding/toml_test.ts deleted file mode 100644 index ab28fa49f..000000000 --- a/std/encoding/toml_test.ts +++ /dev/null @@ -1,479 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assertEquals } from "../testing/asserts.ts"; -import { existsSync } from "../fs/exists.ts"; -import * as path from "../path/mod.ts"; -import { parse, stringify } from "./toml.ts"; - -const moduleDir = path.dirname(path.fromFileUrl(import.meta.url)); -const testdataDir = path.resolve(moduleDir, "testdata"); - -function parseFile(filePath: string): Record<string, unknown> { - if (!existsSync(filePath)) { - throw new Error(`File not found: ${filePath}`); - } - return parse(Deno.readTextFileSync(filePath)); -} - -Deno.test({ - name: "[TOML] Strings", - fn(): void { - const expected = { - strings: { - str0: "deno", - str1: "Roses are not Deno\nViolets are not Deno either", - str2: "Roses are not Deno\nViolets are not Deno either", - str3: "Roses are not Deno\r\nViolets are not Deno either", - str4: 'this is a "quote"', - str5: "The quick brown\nfox jumps over\nthe lazy dog.", - str6: "The quick brown\nfox jumps over\nthe lazy dog.", - lines: "The first newline is\ntrimmed in raw strings.\n All other " + - "whitespace\n is preserved.", - withApostrophe: "What if it's not?", - withSemicolon: `const message = 'hello world';`, - withHexNumberLiteral: - "Prevent bug from stripping string here ->0xabcdef", - withUnicodeChar1: "あ", - withUnicodeChar2: "Deno🦕", - }, - }; - const actual = parseFile(path.join(testdataDir, "string.toml")); - assertEquals(actual, expected); - }, -}); - -Deno.test({ - name: "[TOML] CRLF", - fn(): void { - const expected = { boolean: { bool1: true, bool2: false } }; - const actual = parseFile(path.join(testdataDir, "CRLF.toml")); - assertEquals(actual, expected); - }, -}); - -Deno.test({ - name: "[TOML] Boolean", - fn(): void { - const expected = { boolean: { bool1: true, bool2: false, bool3: true } }; - const actual = parseFile(path.join(testdataDir, "boolean.toml")); - assertEquals(actual, expected); - }, -}); - -Deno.test({ - name: "[TOML] Integer", - fn(): void { - const expected = { - integer: { - int1: 99, - int2: 42, - int3: 0, - int4: -17, - int5: 1000, - int6: 5349221, - int7: 12345, - hex1: "0xDEADBEEF", - hex2: "0xdeadbeef", - hex3: "0xdead_beef", - oct1: "0o01234567", - oct2: "0o755", - bin1: "0b11010110", - }, - }; - const actual = parseFile(path.join(testdataDir, "integer.toml")); - assertEquals(actual, expected); - }, -}); - -Deno.test({ - name: "[TOML] Float", - fn(): void { - const expected = { - float: { - flt1: 1.0, - flt2: 3.1415, - flt3: -0.01, - flt4: 5e22, - flt5: 1e6, - flt6: -2e-2, - flt7: 6.626e-34, - flt8: 224_617.445_991_228, - sf1: Infinity, - sf2: Infinity, - sf3: -Infinity, - sf4: NaN, - sf5: NaN, - sf6: NaN, - }, - }; - const actual = parseFile(path.join(testdataDir, "float.toml")); - assertEquals(actual, expected); - }, -}); - -Deno.test({ - name: "[TOML] Arrays", - fn(): void { - const expected = { - arrays: { - data: [ - ["gamma", "delta"], - [1, 2], - ], - hosts: ["alpha", "omega"], - }, - }; - const actual = parseFile(path.join(testdataDir, "arrays.toml")); - assertEquals(actual, expected); - }, -}); - -Deno.test({ - name: "[TOML] Table", - fn(): void { - const expected = { - deeply: { - nested: { - object: { - in: { - the: { - toml: { - name: "Tom Preston-Werner", - }, - }, - }, - }, - }, - }, - servers: { - alpha: { - ip: "10.0.0.1", - dc: "eqdc10", - }, - beta: { - ip: "10.0.0.2", - dc: "eqdc20", - }, - }, - }; - const actual = parseFile(path.join(testdataDir, "table.toml")); - assertEquals(actual, expected); - }, -}); - -Deno.test({ - name: "[TOML] Simple", - fn(): void { - const expected = { - deno: "is", - not: "[node]", - regex: "<ic*s*>", - NANI: "何?!", - comment: "Comment inside # the comment", - }; - const actual = parseFile(path.join(testdataDir, "simple.toml")); - assertEquals(actual, expected); - }, -}); - -Deno.test({ - name: "[TOML] Datetime", - fn(): void { - const expected = { - datetime: { - odt1: new Date("1979-05-27T07:32:00Z"), - odt2: new Date("1979-05-27T00:32:00-07:00"), - odt3: new Date("1979-05-27T00:32:00.999999-07:00"), - odt4: new Date("1979-05-27 07:32:00Z"), - ld1: new Date("1979-05-27"), - lt1: "07:32:00", - lt2: "00:32:00.999999", - }, - }; - const actual = parseFile(path.join(testdataDir, "datetime.toml")); - assertEquals(actual, expected); - }, -}); - -Deno.test({ - name: "[TOML] Inline Table", - fn(): void { - const expected = { - inlinetable: { - nile: { - also: { - malevolant: { - creation: { - drum: { - kit: "Tama", - }, - }, - }, - }, - derek: { - roddy: "drummer", - }, - }, - name: { - first: "Tom", - last: "Preston-Werner", - }, - point: { - x: 1, - y: 2, - }, - dog: { - type: { - name: "pug", - }, - }, - "tosin.abasi": "guitarist", - animal: { - as: { - leaders: "tosin", - }, - }, - }, - }; - const actual = parseFile(path.join(testdataDir, "inlineTable.toml")); - assertEquals(actual, expected); - }, -}); - -Deno.test({ - name: "[TOML] Array of Tables", - fn(): void { - const expected = { - bin: [ - { name: "deno", path: "cli/main.rs" }, - { name: "deno_core", path: "src/foo.rs" }, - ], - nib: [{ name: "node", path: "not_found" }], - }; - const actual = parseFile(path.join(testdataDir, "arrayTable.toml")); - assertEquals(actual, expected); - }, -}); - -Deno.test({ - name: "[TOML] Cargo", - fn(): void { - const expected = { - workspace: { members: ["./", "core"] }, - bin: [{ name: "deno", path: "cli/main.rs" }], - package: { name: "deno", version: "0.3.4", edition: "2018" }, - dependencies: { - deno_core: { path: "./core" }, - atty: "0.2.11", - dirs: "1.0.5", - flatbuffers: "0.5.0", - futures: "0.1.25", - getopts: "0.2.18", - http: "0.1.16", - hyper: "0.12.24", - "hyper-rustls": "0.16.0", - "integer-atomics": "1.0.2", - lazy_static: "1.3.0", - libc: "0.2.49", - log: "0.4.6", - rand: "0.6.5", - regex: "1.1.0", - remove_dir_all: "0.5.2", - ring: "0.14.6", - rustyline: "3.0.0", - serde_json: "1.0.38", - "source-map-mappings": "0.5.0", - tempfile: "3.0.7", - tokio: "0.1.15", - "tokio-executor": "0.1.6", - "tokio-fs": "0.1.5", - "tokio-io": "0.1.11", - "tokio-process": "0.2.3", - "tokio-threadpool": "0.1.11", - url: "1.7.2", - }, - target: { "cfg(windows)": { dependencies: { winapi: "0.3.6" } } }, - }; - const actual = parseFile(path.join(testdataDir, "cargo.toml")); - assertEquals(actual, expected); - }, -}); - -Deno.test({ - name: "[TOML] Stringify", - fn(): void { - const src = { - foo: { bar: "deno" }, - this: { is: { nested: "denonono" } }, - "https://deno.land/std": { - $: "doller", - }, - "##": { - deno: { - "https://deno.land": { - proto: "https", - ":80": "port", - }, - }, - }, - arrayObjects: [{ stuff: "in" }, {}, { the: "array" }], - deno: "is", - not: "[node]", - regex: "<ic*s*>", - NANI: "何?!", - comment: "Comment inside # the comment", - int1: 99, - int2: 42, - int3: 0, - int4: -17, - int5: 1000, - int6: 5349221, - int7: 12345, - flt1: 1.0, - flt2: 3.1415, - flt3: -0.01, - flt4: 5e22, - flt5: 1e6, - flt6: -2e-2, - flt7: 6.626e-34, - odt1: new Date("1979-05-01T07:32:00Z"), - odt2: new Date("1979-05-27T00:32:00-07:00"), - odt3: new Date("1979-05-27T00:32:00.999999-07:00"), - odt4: new Date("1979-05-27 07:32:00Z"), - ld1: new Date("1979-05-27"), - reg: /foo[bar]/, - sf1: Infinity, - sf2: Infinity, - sf3: -Infinity, - sf4: NaN, - sf5: NaN, - sf6: NaN, - data: [ - ["gamma", "delta"], - [1, 2], - ], - hosts: ["alpha", "omega"], - bool: true, - bool2: false, - }; - const expected = `deno = "is" -not = "[node]" -regex = "<ic*s*>" -NANI = "何?!" -comment = "Comment inside # the comment" -int1 = 99 -int2 = 42 -int3 = 0 -int4 = -17 -int5 = 1000 -int6 = 5349221 -int7 = 12345 -flt1 = 1 -flt2 = 3.1415 -flt3 = -0.01 -flt4 = 5e+22 -flt5 = 1000000 -flt6 = -0.02 -flt7 = 6.626e-34 -odt1 = 1979-05-01T07:32:00.000 -odt2 = 1979-05-27T07:32:00.000 -odt3 = 1979-05-27T07:32:00.999 -odt4 = 1979-05-27T07:32:00.000 -ld1 = 1979-05-27T00:00:00.000 -reg = "/foo[bar]/" -sf1 = inf -sf2 = inf -sf3 = -inf -sf4 = NaN -sf5 = NaN -sf6 = NaN -data = [["gamma","delta"],[1,2]] -hosts = ["alpha","omega"] -bool = true -bool2 = false - -[foo] -bar = "deno" - -[this.is] -nested = "denonono" - -["https://deno.land/std"] -"$" = "doller" - -["##".deno."https://deno.land"] -proto = "https" -":80" = "port" - -[[arrayObjects]] -stuff = "in" - -[[arrayObjects]] - -[[arrayObjects]] -the = "array" -`; - const actual = stringify(src); - assertEquals(actual, expected); - }, -}); - -Deno.test({ - name: "[TOML] Comments", - fn: () => { - const expected = { - str0: "value", - str1: "# This is not a comment", - str2: - " # this is not a comment!\nA multiline string with a #\n# this is also not a comment", - str3: - '"# not a comment"\n\t# this is a real tab on purpose \n# not a comment', - point0: { x: 1, y: 2, str0: "#not a comment", z: 3 }, - point1: { x: 7, y: 8, z: 9, str0: "#not a comment" }, - deno: { - features: ["#secure by default", "supports typescript # not a comment"], - url: "https://deno.land/", - is_not_node: true, - }, - toml: { - name: "Tom's Obvious, Minimal Language", - objectives: ["easy to read", "minimal config file", "#not a comment"], - }, - }; - const actual = parseFile(path.join(testdataDir, "comment.toml")); - assertEquals(actual, expected); - }, -}); - -Deno.test({ - name: "[TOML] Inline Array of Inline Table", - fn(): void { - const expected = { - inlineArray: { - string: [{ var: "a string" }], - my_points: [ - { x: 1, y: 2, z: 3 }, - { x: 7, y: 8, z: 9 }, - { x: 2, y: 4, z: 8 }, - ], - points: [ - { x: 1, y: 2, z: 3 }, - { x: 7, y: 8, z: 9 }, - { x: 2, y: 4, z: 8 }, - ], - }, - }; - const actual = parseFile( - path.join(testdataDir, "inlineArrayOfInlineTable.toml"), - ); - assertEquals(actual, expected); - }, -}); - -Deno.test({ - name: "[TOML] Parse malformed local time as String (#8433)", - fn(): void { - const expected = { sign: "2020-01-01x" }; - const actual = parse(`sign='2020-01-01x'`); - assertEquals(actual, expected); - }, -}); diff --git a/std/encoding/utf8.ts b/std/encoding/utf8.ts deleted file mode 100644 index 6951e37f0..000000000 --- a/std/encoding/utf8.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -/** A default TextEncoder instance */ -export const encoder = new TextEncoder(); - -/** Shorthand for new TextEncoder().encode() */ -export function encode(input?: string): Uint8Array { - return encoder.encode(input); -} - -/** A default TextDecoder instance */ -export const decoder = new TextDecoder(); - -/** Shorthand for new TextDecoder().decode() */ -export function decode(input?: Uint8Array): string { - return decoder.decode(input); -} diff --git a/std/encoding/yaml.ts b/std/encoding/yaml.ts deleted file mode 100644 index 956665244..000000000 --- a/std/encoding/yaml.ts +++ /dev/null @@ -1,17 +0,0 @@ -// 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-2021 the Deno authors. All rights reserved. MIT license. - -export type { ParseOptions } from "./_yaml/parse.ts"; -export { parse, parseAll } from "./_yaml/parse.ts"; -export type { DumpOptions as StringifyOptions } from "./_yaml/stringify.ts"; -export { stringify } from "./_yaml/stringify.ts"; -export type { SchemaDefinition } from "./_yaml/schema.ts"; -export type { StyleVariant } from "./_yaml/type.ts"; -export { - CORE_SCHEMA, - DEFAULT_SCHEMA, - FAILSAFE_SCHEMA, - JSON_SCHEMA, -} from "./_yaml/schema/mod.ts"; diff --git a/std/encoding/yaml_test.ts b/std/encoding/yaml_test.ts deleted file mode 100644 index 90ca9924f..000000000 --- a/std/encoding/yaml_test.ts +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. - -import "./_yaml/parse_test.ts"; -import "./_yaml/stringify_test.ts"; - -// Type check. -import "./yaml.ts"; |