From c9ac07e80cf725f6f98572ce9e4263c9599c250e Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Thu, 9 Nov 2023 17:15:39 +0900 Subject: [PATCH 01/16] test: add toml-test workflow --- .eslintignore | 3 +- .github/FUNDING.yml | 18 +-- .github/workflows/GHPages.yml | 38 ++--- .github/workflows/NewOldBenchmark.yml | 20 +-- .github/workflows/NodeCI.yml | 34 ++--- .github/workflows/toml-test.yml | 28 ++++ .vscode/settings.json | 3 +- toml-test-decode.js | 203 ++++++++++++++++++++++++++ 8 files changed, 290 insertions(+), 57 deletions(-) create mode 100644 .github/workflows/toml-test.yml create mode 100755 toml-test-decode.js diff --git a/.eslintignore b/.eslintignore index fba1edf..387eca5 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,4 +2,5 @@ /coverage /lib /node_modules -/tests/fixtures/**/*.json \ No newline at end of file +/tests/fixtures/**/*.json +!/.github diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index d78d422..3790049 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,12 +1,12 @@ # These are supported funding model platforms github: ota-meshi -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] +patreon: null # Replace with a single Patreon username +open_collective: null # Replace with a single Open Collective username +ko_fi: null # Replace with a single Ko-fi username +tidelift: null # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: null # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: null # Replace with a single Liberapay username +issuehunt: null # Replace with a single IssueHunt username +otechie: null # Replace with a single Otechie username +custom: null # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/workflows/GHPages.yml b/.github/workflows/GHPages.yml index 9d6d845..b0118aa 100644 --- a/.github/workflows/GHPages.yml +++ b/.github/workflows/GHPages.yml @@ -23,22 +23,22 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - - name: Install And Build - run: |+ - npm install - npm run build - cd explorer - npm install - npm run build - - name: Setup Pages - uses: actions/configure-pages@v3 - - name: Upload artifact - uses: actions/upload-pages-artifact@v2 - with: - path: ./explorer/dist - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v2 + - name: Checkout + uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + - name: Install And Build + run: |+ + npm install + npm run build + cd explorer + npm install + npm run build + - name: Setup Pages + uses: actions/configure-pages@v3 + - name: Upload artifact + uses: actions/upload-pages-artifact@v2 + with: + path: ./explorer/dist + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 diff --git a/.github/workflows/NewOldBenchmark.yml b/.github/workflows/NewOldBenchmark.yml index 1e1bbd5..cb32311 100644 --- a/.github/workflows/NewOldBenchmark.yml +++ b/.github/workflows/NewOldBenchmark.yml @@ -10,13 +10,13 @@ jobs: benchmark: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - - name: Setup - run: npm run setup - - name: Install Packages - run: npm install -f - - name: Build - run: npm run build - - name: Benchmark - run: npm run benchmark + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + - name: Setup + run: npm run setup + - name: Install Packages + run: npm install -f + - name: Build + run: npm run build + - name: Benchmark + run: npm run benchmark diff --git a/.github/workflows/NodeCI.yml b/.github/workflows/NodeCI.yml index 77ef3bd..90cd11f 100644 --- a/.github/workflows/NodeCI.yml +++ b/.github/workflows/NodeCI.yml @@ -10,26 +10,26 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - - name: Install Packages - run: npm install -f - - name: Lint - run: npm run lint + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + - name: Install Packages + run: npm install -f + - name: Lint + run: npm run lint test: runs-on: ubuntu-latest strategy: matrix: node-version: [12.x, 14.x, 16.x, 18.x, 20.x] steps: - - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - - name: Setup - run: npm run setup - - name: Install Packages - run: npm install --legacy-peer-deps - - name: Test - run: npm test + - uses: actions/checkout@v4 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + - name: Setup + run: npm run setup + - name: Install Packages + run: npm install --legacy-peer-deps + - name: Test + run: npm test diff --git a/.github/workflows/toml-test.yml b/.github/workflows/toml-test.yml new file mode 100644 index 0000000..99859ee --- /dev/null +++ b/.github/workflows/toml-test.yml @@ -0,0 +1,28 @@ +name: go toml-test + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Install Go + uses: actions/setup-go@v2 + - name: Setup Node.js + uses: actions/setup-node@v4 + - name: Setup + run: npm run setup + - name: Install Packages + run: npm install -f + - name: Build + run: npm run build + - name: Install toml-test + run: go install -v github.com/toml-lang/toml-test/cmd/toml-test@latest + - name: Test + run: node ./toml-test-decode.js diff --git a/.vscode/settings.json b/.vscode/settings.json index 5e3cdde..fdc9239 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,7 +6,8 @@ "typescript", "json", "jsonc", - "yaml" + "yaml", + "github-actions-workflow", ], "typescript.validate.enable": true, "javascript.validate.enable": false, diff --git a/toml-test-decode.js b/toml-test-decode.js new file mode 100755 index 0000000..70fc6df --- /dev/null +++ b/toml-test-decode.js @@ -0,0 +1,203 @@ +#!/usr/bin/env node + +"use strict"; // eslint-disable-line n/shebang -- test + +const fs = require("fs"); +const toml = require("./lib/index.js"); + +/** + * @typedef {import("./src/ast/ast.ts").TOMLValue} TOMLValue + */ + +const resolver = { + Program(node, baseTable = {}) { + return resolveValue(node.body[0], baseTable); + }, + TOMLTopLevelTable(node, baseTable = {}) { + for (const body of node.body) { + resolveValue(body, baseTable); + } + return baseTable; + }, + TOMLKeyValue(node, baseTable = {}) { + const value = resolveValue(node.value); + set(baseTable, resolveValue(node.key), value); + return baseTable; + }, + TOMLTable(node, baseTable = {}) { + const table = getTable( + baseTable, + resolveValue(node.key), + node.kind === "array", + ); + for (const body of node.body) { + resolveValue(body, table); + } + return baseTable; + }, + TOMLArray(node) { + return node.elements.map((e) => resolveValue(e)); + }, + TOMLInlineTable(node) { + const table = {}; + for (const body of node.body) { + resolveValue(body, table); + } + return table; + }, + TOMLKey(node) { + return node.keys.map((key) => resolveValue(key)); + }, + TOMLBare(node) { + return node.name; + }, + TOMLQuoted(node) { + return node.value; + }, + /** @param {TOMLValue} node */ + TOMLValue(node) { + if (node.kind === "boolean") { + return { type: "bool", value: node.value }; + } + if (node.kind === "local-date") { + return { + type: "date-local", + value: node.value.toISOString().slice(0, 10), + }; + } + if (node.kind === "local-date-time") { + return { + type: "datetime-local", + value: node.value.toISOString().slice(0, -1), + }; + } + if (node.kind === "offset-date-time") { + return { + type: "datetime", + value: node.value.toISOString(), + }; + } + if (node.kind === "local-time") { + return { + type: "time-local", + value: node.value.toISOString().slice(11, -1), + }; + } + return { type: node.kind, value: node.value }; + }, +}; + +/** + * Resolve TOML value + */ +function resolveValue(node, baseTable) { + return resolver[node.type](node, baseTable); +} + +let ast = toml.parseTOML(fs.readFileSync(0, "utf-8")); +process.stdout.write(`${JSON.stringify(resolveValue(ast), null, 4)}\n`); + +/** + * Get the table from the table. + */ +function getTable(baseTable, keys, array) { + let target = baseTable; + for (let index = 0; index < keys.length - 1; index++) { + const key = keys[index]; + target = getNextTargetFromKey(target, key); + } + const lastKey = keys.slice(-1)[0]; + const lastTarget = target[lastKey]; + if (lastTarget == null) { + const tableValue = {}; + target[lastKey] = array ? [tableValue] : tableValue; + return tableValue; + } + if (isValue(lastTarget)) { + // Update because it is an invalid value. + const tableValue = {}; + target[lastKey] = array ? [tableValue] : tableValue; + return tableValue; + } + if (!array) { + if (Array.isArray(lastTarget)) { + // Update because it is an invalid value. + const tableValue = {}; + target[lastKey] = tableValue; + return tableValue; + } + return lastTarget; + } + if (Array.isArray(lastTarget)) { + // New record + const tableValue = {}; + lastTarget.push(tableValue); + return tableValue; + } + // Update because it is an invalid value. + const tableValue = {}; + target[lastKey] = [tableValue]; + return tableValue; + + /** Get next target from key */ + function getNextTargetFromKey(currTarget, key) { + const nextTarget = currTarget[key]; + if (nextTarget == null) { + const val = {}; + currTarget[key] = val; + return val; + } + if (isValue(nextTarget)) { + // Update because it is an invalid value. + const val = {}; + currTarget[key] = val; + return val; + } + let resultTarget = nextTarget; + while (Array.isArray(resultTarget)) { + const lastIndex = resultTarget.length - 1; + const nextElement = resultTarget[lastIndex]; + if (isValue(nextElement)) { + // Update because it is an invalid value. + const val = {}; + resultTarget[lastIndex] = val; + return val; + } + resultTarget = nextElement; + } + return resultTarget; + } +} + +/** + * Set the value to the table. + */ +function set(baseTable, keys, value) { + let target = baseTable; + for (let index = 0; index < keys.length - 1; index++) { + const key = keys[index]; + const nextTarget = target[key]; + if (nextTarget == null) { + const val = {}; + target[key] = val; + target = val; + } else { + if (isValue(nextTarget) || Array.isArray(nextTarget)) { + // Update because it is an invalid value. + const val = {}; + target[key] = val; + target = val; + } else { + target = nextTarget; + } + } + } + target[keys.slice(-1)[0]] = value; +} + +/** + * Check whether the given value is a value. + */ +function isValue(value) { + return typeof value !== "object" || value instanceof Date; +} From b1ac115b9732b13b96f7cb6efb7cd9dab5ffda07 Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Thu, 9 Nov 2023 17:34:06 +0900 Subject: [PATCH 02/16] fix --- .github/workflows/toml-test.yml | 2 +- run-toml-test.zsh | 20 ++++++++++++++++++++ toml-test-decode.js | 9 ++++++++- 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100755 run-toml-test.zsh diff --git a/.github/workflows/toml-test.yml b/.github/workflows/toml-test.yml index 99859ee..ae54ca3 100644 --- a/.github/workflows/toml-test.yml +++ b/.github/workflows/toml-test.yml @@ -25,4 +25,4 @@ jobs: - name: Install toml-test run: go install -v github.com/toml-lang/toml-test/cmd/toml-test@latest - name: Test - run: node ./toml-test-decode.js + run: zsh run-toml-test.zsh diff --git a/run-toml-test.zsh b/run-toml-test.zsh new file mode 100755 index 0000000..a0a8ff5 --- /dev/null +++ b/run-toml-test.zsh @@ -0,0 +1,20 @@ +#!/usr/bin/env zsh +# +# Requires toml-test from https://github.com/toml-lang/toml-test + +skip=( + # Invalid UTF-8 strings are not rejected + -skip='invalid/encoding/bad-utf8-*' + + # Certain invalid UTF-8 codepoints are not rejected + -skip='invalid/encoding/bad-codepoint' + + # Certain invalid newline codepoints are not rejected + -skip='invalid/control/rawmulti-cd' + -skip='invalid/control/multi-cr' + -skip='invalid/control/bare-cr' +) + +e=0 +toml-test -int-as-float ${skip[@]} ./toml-test-decode.js || e=1 +exit $e diff --git a/toml-test-decode.js b/toml-test-decode.js index 70fc6df..5f0a6e2 100755 --- a/toml-test-decode.js +++ b/toml-test-decode.js @@ -3,6 +3,7 @@ "use strict"; // eslint-disable-line n/shebang -- test const fs = require("fs"); +/* eslint n/no-missing-require: off -- ignore */ const toml = require("./lib/index.js"); /** @@ -80,7 +81,13 @@ const resolver = { if (node.kind === "local-time") { return { type: "time-local", - value: node.value.toISOString().slice(11, -1), + value: node.datetime.toISOString().slice(11, -1), + }; + } + if (node.kind === "float" || node.kind === "integer") { + return { + type: node.kind, + value: node.number, }; } return { type: node.kind, value: node.value }; From 2a66802d5de941f26aaae2fe5729e97c475560ef Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Thu, 9 Nov 2023 17:36:03 +0900 Subject: [PATCH 03/16] fix --- .github/workflows/toml-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/toml-test.yml b/.github/workflows/toml-test.yml index ae54ca3..a652282 100644 --- a/.github/workflows/toml-test.yml +++ b/.github/workflows/toml-test.yml @@ -25,4 +25,4 @@ jobs: - name: Install toml-test run: go install -v github.com/toml-lang/toml-test/cmd/toml-test@latest - name: Test - run: zsh run-toml-test.zsh + run: run-toml-test.zsh From d3b3b90a9f84ec441357df83c90f9954299e6735 Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Thu, 9 Nov 2023 17:37:21 +0900 Subject: [PATCH 04/16] fix --- .github/workflows/toml-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/toml-test.yml b/.github/workflows/toml-test.yml index a652282..da4e93d 100644 --- a/.github/workflows/toml-test.yml +++ b/.github/workflows/toml-test.yml @@ -25,4 +25,4 @@ jobs: - name: Install toml-test run: go install -v github.com/toml-lang/toml-test/cmd/toml-test@latest - name: Test - run: run-toml-test.zsh + run: ./run-toml-test.zsh From 6f040285fcca9e731b4d933b116b944ede5089bd Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Thu, 9 Nov 2023 18:31:12 +0900 Subject: [PATCH 05/16] fix --- src/utils.ts | 239 ++++++++++++++++++++++++++------------------ toml-test-decode.js | 229 +++++++----------------------------------- 2 files changed, 174 insertions(+), 294 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index a72101c..11feeb8 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -15,103 +15,144 @@ import type { } from "./ast"; import { last } from "./internal-utils"; -type TOMLContentValue = - | TOMLValue["value"] - | TOMLContentValue[] - | TOMLTableValue; +type TOMLContentValue = V | TOMLContentValue[] | TOMLTableValue; -type TOMLTableValue = { - [key: string]: TOMLContentValue; +type TOMLTableValue = { + [key: string]: TOMLContentValue; }; -export function getStaticTOMLValue(node: TOMLValue): TOMLValue["value"]; -export function getStaticTOMLValue(node: TOMLArray): TOMLContentValue[]; -export function getStaticTOMLValue(node: TOMLContentNode): TOMLContentValue; -export function getStaticTOMLValue( - node: - | TOMLProgram - | TOMLTopLevelTable - | TOMLTable - | TOMLKeyValue - | TOMLInlineTable, -): TOMLTableValue; -export function getStaticTOMLValue( - node: TOMLStringValue | TOMLBare | TOMLQuoted, -): string; -export function getStaticTOMLValue(node: TOMLKey): string[]; +export type ConvertTOMLValue = { + (node: TOMLValue): V; + (node: TOMLArray): TOMLContentValue[]; + (node: TOMLContentNode): TOMLContentValue; + ( + node: + | TOMLProgram + | TOMLTopLevelTable + | TOMLTable + | TOMLKeyValue + | TOMLInlineTable, + ): TOMLTableValue; + (node: TOMLStringValue | TOMLBare | TOMLQuoted): string; + (node: TOMLKey): string[]; + (node: TOMLNode): TOMLContentValue | string | string[]; +}; +export type GetStaticTOMLValue = ConvertTOMLValue; /** * Gets the static value for the given node. */ -export function getStaticTOMLValue(node: TOMLNode): TOMLContentValue { - return resolveValue(node); -} +export const getStaticTOMLValue: GetStaticTOMLValue = generateConvertTOMLValue< + TOMLValue["value"] +>((node) => node.value); -/** - * Resolve TOML value - */ -function resolveValue( - node: TOMLNode, - baseTable?: TOMLTableValue, -): TOMLContentValue { - return resolver[node.type](node as never, baseTable); -} +/** Generates a converter to convert from a node. */ +export function generateConvertTOMLValue( + convertValue: (node: TOMLValue) => V, +): ConvertTOMLValue { + function resolveValue(node: TOMLValue, baseTable?: TOMLTableValue): V; + function resolveValue( + node: TOMLArray, + baseTable?: TOMLTableValue, + ): TOMLContentValue[]; + function resolveValue( + node: TOMLContentNode, + baseTable?: TOMLTableValue, + ): TOMLContentValue; + function resolveValue( + node: + | TOMLProgram + | TOMLTopLevelTable + | TOMLTable + | TOMLKeyValue + | TOMLInlineTable, + baseTable?: TOMLTableValue, + ): TOMLTableValue; + function resolveValue( + node: TOMLStringValue | TOMLBare | TOMLQuoted, + baseTable?: TOMLTableValue, + ): string; + function resolveValue(node: TOMLKey, baseTable?: TOMLTableValue): string[]; + function resolveValue( + node: TOMLNode, + baseTable?: TOMLTableValue, + ): TOMLContentValue | string | string[]; -const resolver = { - Program(node: TOMLProgram, baseTable: TOMLTableValue = {}) { - return resolveValue(node.body[0], baseTable); - }, - TOMLTopLevelTable(node: TOMLTopLevelTable, baseTable: TOMLTableValue = {}) { - for (const body of node.body) { - resolveValue(body, baseTable); - } - return baseTable; - }, - TOMLKeyValue(node: TOMLKeyValue, baseTable: TOMLTableValue = {}) { - const value = resolveValue(node.value); - set(baseTable, getStaticTOMLValue(node.key), value); - return baseTable; - }, - TOMLTable(node: TOMLTable, baseTable: TOMLTableValue = {}) { - const table = getTable( - baseTable, - getStaticTOMLValue(node.key), - node.kind === "array", - ); - for (const body of node.body) { - resolveValue(body, table); - } - return baseTable; - }, - TOMLArray(node: TOMLArray) { - return node.elements.map((e) => getStaticTOMLValue(e)); - }, - TOMLInlineTable(node: TOMLInlineTable) { - const table: TOMLTableValue = {}; - for (const body of node.body) { - resolveValue(body, table); - } - return table; - }, - TOMLKey(node: TOMLKey) { - return node.keys.map((key) => getStaticTOMLValue(key)); - }, - TOMLBare(node: TOMLBare) { - return node.name; - }, - TOMLQuoted(node: TOMLQuoted) { - return node.value; - }, - TOMLValue(node: TOMLValue) { - return node.value; - }, -}; + /** + * Resolve TOML value + */ + function resolveValue( + node: TOMLNode, + baseTable?: TOMLTableValue, + ): TOMLContentValue | string | string[] { + return resolver[node.type](node as never, baseTable); + } + + const resolver = { + Program(node: TOMLProgram, baseTable: TOMLTableValue = {}) { + return resolveValue(node.body[0], baseTable); + }, + TOMLTopLevelTable( + node: TOMLTopLevelTable, + baseTable: TOMLTableValue = {}, + ) { + for (const body of node.body) { + resolveValue(body, baseTable); + } + return baseTable; + }, + TOMLKeyValue(node: TOMLKeyValue, baseTable: TOMLTableValue = {}) { + const value = resolveValue(node.value); + set(baseTable, resolveValue(node.key), value); + return baseTable; + }, + TOMLTable(node: TOMLTable, baseTable: TOMLTableValue = {}) { + const table = getTable( + baseTable, + resolveValue(node.key), + node.kind === "array", + ); + for (const body of node.body) { + resolveValue(body, table); + } + return baseTable; + }, + TOMLArray(node: TOMLArray) { + return node.elements.map((e) => resolveValue(e)); + }, + TOMLInlineTable(node: TOMLInlineTable) { + const table: TOMLTableValue = {}; + for (const body of node.body) { + resolveValue(body, table); + } + return table; + }, + TOMLKey(node: TOMLKey) { + return node.keys.map((key) => resolveValue(key)); + }, + TOMLBare(node: TOMLBare) { + return node.name; + }, + TOMLQuoted(node: TOMLQuoted) { + return node.value; + }, + TOMLValue(node: TOMLValue) { + return convertValue(node); + }, + }; + + return (node: TOMLNode) => resolveValue(node) as never; +} /** * Get the table from the table. */ -function getTable(baseTable: TOMLTableValue, keys: string[], array: boolean) { - let target: TOMLTableValue = baseTable; +function getTable( + baseTable: TOMLTableValue, + keys: string[], + array: boolean, +) { + let target: TOMLTableValue = baseTable; for (let index = 0; index < keys.length - 1; index++) { const key = keys[index]; target = getNextTargetFromKey(target, key); @@ -119,20 +160,20 @@ function getTable(baseTable: TOMLTableValue, keys: string[], array: boolean) { const lastKey = last(keys)!; const lastTarget = target[lastKey]; if (lastTarget == null) { - const tableValue: TOMLTableValue = {}; + const tableValue: TOMLTableValue = {}; target[lastKey] = array ? [tableValue] : tableValue; return tableValue; } if (isValue(lastTarget)) { // Update because it is an invalid value. - const tableValue: TOMLTableValue = {}; + const tableValue: TOMLTableValue = {}; target[lastKey] = array ? [tableValue] : tableValue; return tableValue; } if (!array) { if (Array.isArray(lastTarget)) { // Update because it is an invalid value. - const tableValue: TOMLTableValue = {}; + const tableValue: TOMLTableValue = {}; target[lastKey] = tableValue; return tableValue; } @@ -141,29 +182,29 @@ function getTable(baseTable: TOMLTableValue, keys: string[], array: boolean) { if (Array.isArray(lastTarget)) { // New record - const tableValue: TOMLTableValue = {}; + const tableValue: TOMLTableValue = {}; lastTarget.push(tableValue); return tableValue; } // Update because it is an invalid value. - const tableValue: TOMLTableValue = {}; + const tableValue: TOMLTableValue = {}; target[lastKey] = [tableValue]; return tableValue; /** Get next target from key */ function getNextTargetFromKey( - currTarget: TOMLTableValue, + currTarget: TOMLTableValue, key: string, - ): TOMLTableValue { + ): TOMLTableValue { const nextTarget = currTarget[key]; if (nextTarget == null) { - const val: TOMLTableValue = {}; + const val: TOMLTableValue = {}; currTarget[key] = val; return val; } if (isValue(nextTarget)) { // Update because it is an invalid value. - const val: TOMLTableValue = {}; + const val: TOMLTableValue = {}; currTarget[key] = val; return val; } @@ -174,7 +215,7 @@ function getTable(baseTable: TOMLTableValue, keys: string[], array: boolean) { const nextElement = resultTarget[lastIndex]; if (isValue(nextElement)) { // Update because it is an invalid value. - const val: TOMLTableValue = {}; + const val: TOMLTableValue = {}; resultTarget[lastIndex] = val; return val; } @@ -187,19 +228,19 @@ function getTable(baseTable: TOMLTableValue, keys: string[], array: boolean) { /** * Set the value to the table. */ -function set(baseTable: TOMLTableValue, keys: string[], value: any) { - let target: TOMLTableValue = baseTable; +function set(baseTable: TOMLTableValue, keys: string[], value: any) { + let target: TOMLTableValue = baseTable; for (let index = 0; index < keys.length - 1; index++) { const key = keys[index]; const nextTarget = target[key]; if (nextTarget == null) { - const val: TOMLTableValue = {}; + const val: TOMLTableValue = {}; target[key] = val; target = val; } else { if (isValue(nextTarget) || Array.isArray(nextTarget)) { // Update because it is an invalid value. - const val: TOMLTableValue = {}; + const val: TOMLTableValue = {}; target[key] = val; target = val; } else { @@ -213,6 +254,6 @@ function set(baseTable: TOMLTableValue, keys: string[], value: any) { /** * Check whether the given value is a value. */ -function isValue(value: any): value is TOMLValue["value"] { +function isValue(value: TOMLContentValue): value is V { return typeof value !== "object" || value instanceof Date; } diff --git a/toml-test-decode.js b/toml-test-decode.js index 5f0a6e2..70c69e1 100755 --- a/toml-test-decode.js +++ b/toml-test-decode.js @@ -5,206 +5,45 @@ const fs = require("fs"); /* eslint n/no-missing-require: off -- ignore */ const toml = require("./lib/index.js"); +const { generateConvertTOMLValue } = require("./lib/utils.js"); -/** - * @typedef {import("./src/ast/ast.ts").TOMLValue} TOMLValue - */ - -const resolver = { - Program(node, baseTable = {}) { - return resolveValue(node.body[0], baseTable); - }, - TOMLTopLevelTable(node, baseTable = {}) { - for (const body of node.body) { - resolveValue(body, baseTable); - } - return baseTable; - }, - TOMLKeyValue(node, baseTable = {}) { - const value = resolveValue(node.value); - set(baseTable, resolveValue(node.key), value); - return baseTable; - }, - TOMLTable(node, baseTable = {}) { - const table = getTable( - baseTable, - resolveValue(node.key), - node.kind === "array", - ); - for (const body of node.body) { - resolveValue(body, table); - } - return baseTable; - }, - TOMLArray(node) { - return node.elements.map((e) => resolveValue(e)); - }, - TOMLInlineTable(node) { - const table = {}; - for (const body of node.body) { - resolveValue(body, table); - } - return table; - }, - TOMLKey(node) { - return node.keys.map((key) => resolveValue(key)); - }, - TOMLBare(node) { - return node.name; - }, - TOMLQuoted(node) { - return node.value; - }, - /** @param {TOMLValue} node */ - TOMLValue(node) { - if (node.kind === "boolean") { - return { type: "bool", value: node.value }; - } - if (node.kind === "local-date") { - return { - type: "date-local", - value: node.value.toISOString().slice(0, 10), - }; - } - if (node.kind === "local-date-time") { - return { - type: "datetime-local", - value: node.value.toISOString().slice(0, -1), - }; - } - if (node.kind === "offset-date-time") { - return { - type: "datetime", - value: node.value.toISOString(), - }; - } - if (node.kind === "local-time") { - return { - type: "time-local", - value: node.datetime.toISOString().slice(11, -1), - }; - } - if (node.kind === "float" || node.kind === "integer") { - return { - type: node.kind, - value: node.number, - }; - } - return { type: node.kind, value: node.value }; - }, -}; - -/** - * Resolve TOML value - */ -function resolveValue(node, baseTable) { - return resolver[node.type](node, baseTable); -} - -let ast = toml.parseTOML(fs.readFileSync(0, "utf-8")); -process.stdout.write(`${JSON.stringify(resolveValue(ast), null, 4)}\n`); - -/** - * Get the table from the table. - */ -function getTable(baseTable, keys, array) { - let target = baseTable; - for (let index = 0; index < keys.length - 1; index++) { - const key = keys[index]; - target = getNextTargetFromKey(target, key); +/** Converter for toml-test (https://github.com/toml-lang/toml-test). */ +const convertTomlTestValue = generateConvertTOMLValue((node) => { + if (node.kind === "boolean") { + return { type: "bool", value: String(node.value) }; } - const lastKey = keys.slice(-1)[0]; - const lastTarget = target[lastKey]; - if (lastTarget == null) { - const tableValue = {}; - target[lastKey] = array ? [tableValue] : tableValue; - return tableValue; + if (node.kind === "local-date") { + return { + type: "date-local", + value: node.value.toISOString().slice(0, 10), + }; } - if (isValue(lastTarget)) { - // Update because it is an invalid value. - const tableValue = {}; - target[lastKey] = array ? [tableValue] : tableValue; - return tableValue; + if (node.kind === "local-date-time") { + return { + type: "datetime-local", + value: node.value.toISOString().slice(0, -1), + }; } - if (!array) { - if (Array.isArray(lastTarget)) { - // Update because it is an invalid value. - const tableValue = {}; - target[lastKey] = tableValue; - return tableValue; - } - return lastTarget; + if (node.kind === "offset-date-time") { + return { + type: "datetime", + value: node.value.toISOString(), + }; } - if (Array.isArray(lastTarget)) { - // New record - const tableValue = {}; - lastTarget.push(tableValue); - return tableValue; + if (node.kind === "local-time") { + return { + type: "time-local", + value: node.value.toISOString().slice(11, -1), + }; } - // Update because it is an invalid value. - const tableValue = {}; - target[lastKey] = [tableValue]; - return tableValue; - - /** Get next target from key */ - function getNextTargetFromKey(currTarget, key) { - const nextTarget = currTarget[key]; - if (nextTarget == null) { - const val = {}; - currTarget[key] = val; - return val; - } - if (isValue(nextTarget)) { - // Update because it is an invalid value. - const val = {}; - currTarget[key] = val; - return val; - } - let resultTarget = nextTarget; - while (Array.isArray(resultTarget)) { - const lastIndex = resultTarget.length - 1; - const nextElement = resultTarget[lastIndex]; - if (isValue(nextElement)) { - // Update because it is an invalid value. - const val = {}; - resultTarget[lastIndex] = val; - return val; - } - resultTarget = nextElement; - } - return resultTarget; - } -} - -/** - * Set the value to the table. - */ -function set(baseTable, keys, value) { - let target = baseTable; - for (let index = 0; index < keys.length - 1; index++) { - const key = keys[index]; - const nextTarget = target[key]; - if (nextTarget == null) { - const val = {}; - target[key] = val; - target = val; - } else { - if (isValue(nextTarget) || Array.isArray(nextTarget)) { - // Update because it is an invalid value. - const val = {}; - target[key] = val; - target = val; - } else { - target = nextTarget; - } - } + if (node.kind === "float" || node.kind === "integer") { + return { + type: node.kind, + value: node.number, + }; } - target[keys.slice(-1)[0]] = value; -} + return { type: node.kind, value: node.value }; +}); -/** - * Check whether the given value is a value. - */ -function isValue(value) { - return typeof value !== "object" || value instanceof Date; -} +const ast = toml.parseTOML(fs.readFileSync(0, "utf-8")); +process.stdout.write(`${JSON.stringify(convertTomlTestValue(ast), null, 4)}\n`); From af2be13c0af6e275529f87a73bf7b6972b8dabc1 Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Thu, 9 Nov 2023 18:40:02 +0900 Subject: [PATCH 06/16] fix --- .eslintignore | 1 + .github/workflows/toml-test.yml | 2 +- .gitignore | 3 ++- run-toml-test.zsh => run-toml-test.sh | 5 ++++- toml-test-decode.js | 4 +++- 5 files changed, 11 insertions(+), 4 deletions(-) rename run-toml-test.zsh => run-toml-test.sh (87%) diff --git a/.eslintignore b/.eslintignore index 387eca5..15e77ab 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,3 +4,4 @@ /node_modules /tests/fixtures/**/*.json !/.github +/toml-test-decode-last-result.json diff --git a/.github/workflows/toml-test.yml b/.github/workflows/toml-test.yml index da4e93d..b40ed75 100644 --- a/.github/workflows/toml-test.yml +++ b/.github/workflows/toml-test.yml @@ -25,4 +25,4 @@ jobs: - name: Install toml-test run: go install -v github.com/toml-lang/toml-test/cmd/toml-test@latest - name: Test - run: ./run-toml-test.zsh + run: ./run-toml-test.sh diff --git a/.gitignore b/.gitignore index 939833c..32068f5 100644 --- a/.gitignore +++ b/.gitignore @@ -103,4 +103,5 @@ dist # TernJS port file .tern-port -/lib \ No newline at end of file +/lib +/toml-test-decode-last-result.json diff --git a/run-toml-test.zsh b/run-toml-test.sh similarity index 87% rename from run-toml-test.zsh rename to run-toml-test.sh index a0a8ff5..090e2c2 100755 --- a/run-toml-test.zsh +++ b/run-toml-test.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env zsh +#!/usr/bin/env sh # # Requires toml-test from https://github.com/toml-lang/toml-test @@ -13,6 +13,9 @@ skip=( -skip='invalid/control/rawmulti-cd' -skip='invalid/control/multi-cr' -skip='invalid/control/bare-cr' + + # Debug + # -run 'valid/table/with-single-quotes' ) e=0 diff --git a/toml-test-decode.js b/toml-test-decode.js index 70c69e1..5d8916d 100755 --- a/toml-test-decode.js +++ b/toml-test-decode.js @@ -46,4 +46,6 @@ const convertTomlTestValue = generateConvertTOMLValue((node) => { }); const ast = toml.parseTOML(fs.readFileSync(0, "utf-8")); -process.stdout.write(`${JSON.stringify(convertTomlTestValue(ast), null, 4)}\n`); +const result = `${JSON.stringify(convertTomlTestValue(ast), null, 4)}\n`; +process.stdout.write(result); +fs.writeFileSync("toml-test-decode-last-result.json", result); From 31ec2130f2d6f78a25ea6b0ac0eb1cd127984ef0 Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Thu, 9 Nov 2023 18:51:39 +0900 Subject: [PATCH 07/16] fix: wrong value of `bigint` in binary `TOMLIntegerValue` --- run-toml-test.sh | 2 +- src/tokenizer/tokenizer.ts | 2 +- toml-test-decode.js | 14 ++++++++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/run-toml-test.sh b/run-toml-test.sh index 090e2c2..81fb56d 100755 --- a/run-toml-test.sh +++ b/run-toml-test.sh @@ -19,5 +19,5 @@ skip=( ) e=0 -toml-test -int-as-float ${skip[@]} ./toml-test-decode.js || e=1 +toml-test ${skip[@]} ./toml-test-decode.js || e=1 exit $e diff --git a/src/tokenizer/tokenizer.ts b/src/tokenizer/tokenizer.ts index c9d58f2..209a79a 100644 --- a/src/tokenizer/tokenizer.ts +++ b/src/tokenizer/tokenizer.ts @@ -66,7 +66,7 @@ const RADIX_PREFIXES = { 16: "0x", 10: "", 8: "0o", - 2: "02", + 2: "0b", }; const ESCAPES_1_0: Record = { diff --git a/toml-test-decode.js b/toml-test-decode.js index 5d8916d..4315295 100755 --- a/toml-test-decode.js +++ b/toml-test-decode.js @@ -36,16 +36,22 @@ const convertTomlTestValue = generateConvertTOMLValue((node) => { value: node.value.toISOString().slice(11, -1), }; } - if (node.kind === "float" || node.kind === "integer") { + if (node.kind === "float") { return { type: node.kind, - value: node.number, + value: String(node.value), + }; + } + if (node.kind === "integer") { + return { + type: node.kind, + value: String(node.bigint), }; } return { type: node.kind, value: node.value }; }); const ast = toml.parseTOML(fs.readFileSync(0, "utf-8")); -const result = `${JSON.stringify(convertTomlTestValue(ast), null, 4)}\n`; +const result = `${JSON.stringify(convertTomlTestValue(ast), null, 2)}\n`; process.stdout.write(result); -fs.writeFileSync("toml-test-decode-last-result.json", result); +// fs.writeFileSync("toml-test-decode-last-result.json", result); From f2dc29afa384c550136a042a3c9ae7b2517c00f5 Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Thu, 9 Nov 2023 18:51:55 +0900 Subject: [PATCH 08/16] Create blue-cameras-roll.md --- .changeset/blue-cameras-roll.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/blue-cameras-roll.md diff --git a/.changeset/blue-cameras-roll.md b/.changeset/blue-cameras-roll.md new file mode 100644 index 0000000..6a5510a --- /dev/null +++ b/.changeset/blue-cameras-roll.md @@ -0,0 +1,5 @@ +--- +"toml-eslint-parser": patch +--- + +fix: wrong value of `bigint` in binary `TOMLIntegerValue` From e5ce42d98c40fb31b443760512b8152b3bcaabf7 Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Thu, 9 Nov 2023 18:53:03 +0900 Subject: [PATCH 09/16] Create ten-paws-decide.md --- .changeset/ten-paws-decide.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/ten-paws-decide.md diff --git a/.changeset/ten-paws-decide.md b/.changeset/ten-paws-decide.md new file mode 100644 index 0000000..1399f79 --- /dev/null +++ b/.changeset/ten-paws-decide.md @@ -0,0 +1,5 @@ +--- +"toml-eslint-parser": minor +--- + +refactor for getStaticTOMLValue From 3a3abf002c87808e465d2ddd972eb72470cd5c7a Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Thu, 9 Nov 2023 18:57:04 +0900 Subject: [PATCH 10/16] fix --- .github/workflows/toml-test.yml | 3 ++- run-toml-test.sh => run-toml-test.zsh | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) rename run-toml-test.sh => run-toml-test.zsh (96%) diff --git a/.github/workflows/toml-test.yml b/.github/workflows/toml-test.yml index b40ed75..50c7b56 100644 --- a/.github/workflows/toml-test.yml +++ b/.github/workflows/toml-test.yml @@ -25,4 +25,5 @@ jobs: - name: Install toml-test run: go install -v github.com/toml-lang/toml-test/cmd/toml-test@latest - name: Test - run: ./run-toml-test.sh + run: ./run-toml-test.zsh + shell: zsh diff --git a/run-toml-test.sh b/run-toml-test.zsh similarity index 96% rename from run-toml-test.sh rename to run-toml-test.zsh index 81fb56d..fd7d38a 100755 --- a/run-toml-test.sh +++ b/run-toml-test.zsh @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/usr/bin/env zsh # # Requires toml-test from https://github.com/toml-lang/toml-test From d23cbdb549aa283ec2317c083c72aaf7ae6293d0 Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Thu, 9 Nov 2023 18:58:51 +0900 Subject: [PATCH 11/16] fix --- .github/workflows/toml-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/toml-test.yml b/.github/workflows/toml-test.yml index 50c7b56..779f291 100644 --- a/.github/workflows/toml-test.yml +++ b/.github/workflows/toml-test.yml @@ -26,4 +26,4 @@ jobs: run: go install -v github.com/toml-lang/toml-test/cmd/toml-test@latest - name: Test run: ./run-toml-test.zsh - shell: zsh + shell: zsh {0} From 7dab9be3176850e62ba547c0798e1ea3b605ae76 Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Thu, 9 Nov 2023 19:09:49 +0900 Subject: [PATCH 12/16] fix --- run-toml-test.zsh | 2 -- 1 file changed, 2 deletions(-) diff --git a/run-toml-test.zsh b/run-toml-test.zsh index fd7d38a..dd8e26b 100755 --- a/run-toml-test.zsh +++ b/run-toml-test.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh -# # Requires toml-test from https://github.com/toml-lang/toml-test skip=( From 35cde59c65b144b9e5fef02411654928560e131f Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Thu, 9 Nov 2023 19:14:18 +0900 Subject: [PATCH 13/16] fix --- .github/workflows/toml-test.yml | 2 ++ run-toml-test.zsh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/toml-test.yml b/.github/workflows/toml-test.yml index 779f291..b7b4d50 100644 --- a/.github/workflows/toml-test.yml +++ b/.github/workflows/toml-test.yml @@ -16,6 +16,8 @@ jobs: uses: actions/setup-go@v2 - name: Setup Node.js uses: actions/setup-node@v4 + - name: Install zsh + run: sudo apt-get update; sudo apt-get install zsh - name: Setup run: npm run setup - name: Install Packages diff --git a/run-toml-test.zsh b/run-toml-test.zsh index dd8e26b..fd7d38a 100755 --- a/run-toml-test.zsh +++ b/run-toml-test.zsh @@ -1,3 +1,5 @@ +#!/usr/bin/env zsh +# # Requires toml-test from https://github.com/toml-lang/toml-test skip=( From a0c22a02f2399543f02f75590ff9aac423912e4b Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Thu, 9 Nov 2023 19:19:33 +0900 Subject: [PATCH 14/16] fix --- .github/workflows/toml-test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/toml-test.yml b/.github/workflows/toml-test.yml index b7b4d50..1fb5b38 100644 --- a/.github/workflows/toml-test.yml +++ b/.github/workflows/toml-test.yml @@ -26,6 +26,8 @@ jobs: run: npm run build - name: Install toml-test run: go install -v github.com/toml-lang/toml-test/cmd/toml-test@latest + - name: Setup PATH + run: export PATH="$(go env GOPATH)/bin:$PATH" - name: Test run: ./run-toml-test.zsh shell: zsh {0} From ae50c60f854d70d0d306232efe793ff159592529 Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Thu, 9 Nov 2023 19:23:32 +0900 Subject: [PATCH 15/16] update --- .github/workflows/toml-test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/toml-test.yml b/.github/workflows/toml-test.yml index 1fb5b38..f8c5ff9 100644 --- a/.github/workflows/toml-test.yml +++ b/.github/workflows/toml-test.yml @@ -26,8 +26,8 @@ jobs: run: npm run build - name: Install toml-test run: go install -v github.com/toml-lang/toml-test/cmd/toml-test@latest - - name: Setup PATH - run: export PATH="$(go env GOPATH)/bin:$PATH" - name: Test - run: ./run-toml-test.zsh + run: | + export PATH="$(go env GOPATH)/bin:$PATH" + ./run-toml-test.zsh shell: zsh {0} From 997b1c62c9c2f527083aec0fa1445162daeb5fc5 Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Thu, 9 Nov 2023 19:28:13 +0900 Subject: [PATCH 16/16] fix --- toml-test-decode.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/toml-test-decode.js b/toml-test-decode.js index 4315295..74ea598 100755 --- a/toml-test-decode.js +++ b/toml-test-decode.js @@ -39,7 +39,14 @@ const convertTomlTestValue = generateConvertTOMLValue((node) => { if (node.kind === "float") { return { type: node.kind, - value: String(node.value), + value: + node.value === Infinity + ? "+inf" + : node.value === -Infinity + ? "-inf" + : Number.isNaN(node.value) + ? "nan" + : String(node.value), }; } if (node.kind === "integer") {