diff --git a/.licenses/npm/smol-toml.dep.yml b/.licenses/npm/smol-toml.dep.yml new file mode 100644 index 00000000..720466b1 Binary files /dev/null and b/.licenses/npm/smol-toml.dep.yml differ diff --git a/README.md b/README.md index de8d2ae3..ab2a8afc 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ See [action.yml](action.yml) # Examples: 12.x, 10.15.1, >=10.15.0, lts/Hydrogen, 16-nightly, latest, node node-version: '' - # File containing the version Spec of the version to use. Examples: package.json, .nvmrc, .node-version, .tool-versions. + # File containing the version Spec of the version to use. Examples: package.json, mise.toml, .nvmrc, .node-version, .tool-versions. # If node-version and node-version-file are both provided the action will use version from node-version. node-version-file: '' diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index 4d7a79a0..e2f90be8 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -1,18 +1,18 @@ +import * as cache from '@actions/cache'; import * as core from '@actions/core'; import * as exec from '@actions/exec'; -import * as tc from '@actions/tool-cache'; -import * as cache from '@actions/cache'; import * as io from '@actions/io'; +import * as tc from '@actions/tool-cache'; import fs from 'fs'; -import path from 'path'; import osm from 'os'; +import path from 'path'; import each from 'jest-each'; +import OfficialBuilds from '../src/distributions/official_builds/official_builds'; import * as main from '../src/main'; import * as util from '../src/util'; -import OfficialBuilds from '../src/distributions/official_builds/official_builds'; describe('main tests', () => { let inputs = {} as any; @@ -112,6 +112,11 @@ describe('main tests', () => { ${'{"engines": {"node": "17.0.0"}}'} | ${'17.0.0'} ${'{"devEngines": {"runtime": {"name": "node", "version": "22.0.0"}}}'} | ${'22.0.0'} ${'{"devEngines": {"runtime": [{"name": "bun"}, {"name": "node", "version": "22.0.0"}]}}'} | ${'22.0.0'} + ${'[tools]\ngo="latest"\nnode = "24.10"'} | ${'24.10'} + ${'[tools]\nnode = "22.12"'} | ${'22.12'} + ${'[tools]\ngo="latest"\nnode = "24.10"'} | ${'24.10'} + ${'[tools]\nnode = { version = "22.20" }'} | ${'22.20'} + ${'[tools]\nnode = { postinstall = "corepack enable" }'} | ${null} `.it('parses "$contents"', ({contents, expected}) => { const existsSpy = jest.spyOn(fs, 'existsSync'); existsSpy.mockImplementation(() => true); diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js index d83e4de6..096d332d 100644 --- a/dist/cache-save/index.js +++ b/dist/cache-save/index.js @@ -46968,6 +46968,7 @@ exports.printEnvDetailsAndSetOutput = printEnvDetailsAndSetOutput; const core = __importStar(__nccwpck_require__(37484)); const exec = __importStar(__nccwpck_require__(95236)); const io = __importStar(__nccwpck_require__(94994)); +const smol_toml_1 = __nccwpck_require__(27106); const fs_1 = __importDefault(__nccwpck_require__(79896)); const path_1 = __importDefault(__nccwpck_require__(16928)); function getNodeVersionFromFile(versionFilePath) { @@ -47021,6 +47022,23 @@ function getNodeVersionFromFile(versionFilePath) { catch { core.info('Node version file is not JSON file'); } + // Try parsing the file as a mise `mise.toml` file. + try { + const manifest = (0, smol_toml_1.parse)(contents); + if (manifest?.tools?.node) { + const node = manifest.tools.node; + if (typeof node === 'object' && node?.version) { + return node.version; + } + if (typeof node === 'string') { + return node; + } + return null; + } + } + catch { + core.info('Node version file is not TOML file'); + } const found = contents.match(/^(?:node(js)?\s+)?v?(?[^\s]+)$/m); return found?.groups?.version ?? contents.trim(); } @@ -88489,6 +88507,721 @@ function randomUUID() { /***/ }), +/***/ 27106: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; +/*! +* Copyright (c) Squirrel Chat et al., All rights reserved. +* SPDX-License-Identifier: BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the copyright holder nor the names of its contributors +* may be used to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +Object.defineProperties(exports, { + __esModule: { value: true }, + [Symbol.toStringTag]: { value: "Module" } +}); +//#region src/date.ts +let DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i; +var TomlDate = class TomlDate extends Date { + #hasDate = false; + #hasTime = false; + #offset = null; + constructor(date) { + let hasDate = true; + let hasTime = true; + let offset = "Z"; + if (typeof date === "string") { + let match = date.match(DATE_TIME_RE); + if (match) { + if (!match[1]) { + hasDate = false; + date = `0000-01-01T${date}`; + } + hasTime = !!match[2]; + hasTime && date[10] === " " && (date = date.replace(" ", "T")); + if (match[2] && +match[2] > 23) date = ""; + else { + offset = match[3] || null; + date = date.toUpperCase(); + if (!offset && hasTime) date += "Z"; + } + } else date = ""; + } + super(date); + if (!isNaN(this.getTime())) { + this.#hasDate = hasDate; + this.#hasTime = hasTime; + this.#offset = offset; + } + } + isDateTime() { + return this.#hasDate && this.#hasTime; + } + isLocal() { + return !this.#hasDate || !this.#hasTime || !this.#offset; + } + isDate() { + return this.#hasDate && !this.#hasTime; + } + isTime() { + return this.#hasTime && !this.#hasDate; + } + isValid() { + return this.#hasDate || this.#hasTime; + } + toISOString() { + let iso = super.toISOString(); + if (this.isDate()) return iso.slice(0, 10); + if (this.isTime()) return iso.slice(11, 23); + if (this.#offset === null) return iso.slice(0, -1); + if (this.#offset === "Z") return iso; + let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6); + offset = this.#offset[0] === "-" ? offset : -offset; + return (/* @__PURE__ */ new Date(this.getTime() - offset * 6e4)).toISOString().slice(0, -1) + this.#offset; + } + static wrapAsOffsetDateTime(jsDate, offset = "Z") { + let date = new TomlDate(jsDate); + date.#offset = offset; + return date; + } + static wrapAsLocalDateTime(jsDate) { + let date = new TomlDate(jsDate); + date.#offset = null; + return date; + } + static wrapAsLocalDate(jsDate) { + let date = new TomlDate(jsDate); + date.#hasTime = false; + date.#offset = null; + return date; + } + static wrapAsLocalTime(jsDate) { + let date = new TomlDate(jsDate); + date.#hasDate = false; + date.#offset = null; + return date; + } +}; +//#endregion +//#region src/error.ts +function getLineColFromPtr(string, ptr) { + let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g); + return [lines.length, lines.pop().length + 1]; +} +function makeCodeBlock(string, line, column) { + let lines = string.split(/\r\n|\n|\r/g); + let codeblock = ""; + let numberLen = (Math.log10(line + 1) | 0) + 1; + for (let i = line - 1; i <= line + 1; i++) { + let l = lines[i - 1]; + if (!l) continue; + codeblock += i.toString().padEnd(numberLen, " "); + codeblock += ": "; + codeblock += l; + codeblock += "\n"; + if (i === line) { + codeblock += " ".repeat(numberLen + column + 2); + codeblock += "^\n"; + } + } + return codeblock; +} +var TomlError = class extends Error { + line; + column; + codeblock; + constructor(message, options) { + const [line, column] = getLineColFromPtr(options.toml, options.ptr); + const codeblock = makeCodeBlock(options.toml, line, column); + super(`Invalid TOML document: ${message}\n\n${codeblock}`, options); + this.line = line; + this.column = column; + this.codeblock = codeblock; + } +}; +//#endregion +//#region src/primitive.ts +let INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/; +let FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/; +let LEADING_ZERO = /^[+-]?0[0-9_]/; +function parseString(str, ptr) { + let c = str[ptr++]; + let first = c; + let isLiteral = c === "'"; + let isMultiline = c === str[ptr] && c === str[ptr + 1]; + if (isMultiline) { + if (str[ptr += 2] === "\n") ptr++; + else if (str[ptr] === "\r" && str[ptr + 1] === "\n") ptr += 2; + } + let parsed = ""; + let sliceStart = ptr; + let state = 0; + for (let i = ptr; i < str.length; i++) { + c = str[i]; + if (isMultiline && (c === "\n" || c === "\r" && str[i + 1] === "\n")) state = state && 3; + else if (c < " " && c !== " " || c === "") throw new TomlError("control characters are not allowed in strings", { + toml: str, + ptr: i + }); + else if ((!state || state === 3) && c === first && (!isMultiline || str[i + 1] === first && str[i + 2] === first)) { + if (isMultiline) { + if (str[i + 3] === first) i++; + if (str[i + 3] === first) i++; + } + return [state ? parsed : parsed + str.slice(sliceStart, i), i + (isMultiline ? 3 : 1)]; + } else if (!state) { + if (!isLiteral && c === "\\") { + parsed += str.slice(sliceStart, sliceStart = i); + state = 1; + } + } else if (state === 1) if (c === "x" || c === "u" || c === "U") { + let value = 0; + let len = c === "x" ? 2 : c === "u" ? 4 : 8; + for (let j = 0; j < len; j++, i++) { + let hex = str.charCodeAt(i + 1); + let digit = hex >= 48 && hex <= 57 ? hex - 48 : hex >= 65 && hex <= 70 ? hex - 65 + 10 : hex >= 97 && hex <= 102 ? hex - 97 + 10 : -1; + if (digit < 0) throw new TomlError("invalid non-hex character in unicode escape", { + toml: str, + ptr: i + 1 + }); + value = value << 4 | digit; + } + if (value < 0 || value > 1114111 || value >= 55296 && value <= 57343) throw new TomlError("invalid unicode escape", { + toml: str, + ptr: i + }); + parsed += String.fromCodePoint(value); + sliceStart = i + 1; + state = 0; + } else if (c === " " || c === " ") state = 2; + else { + if (c === "b") parsed += "\b"; + else if (c === "t") parsed += " "; + else if (c === "n") parsed += "\n"; + else if (c === "f") parsed += "\f"; + else if (c === "r") parsed += "\r"; + else if (c === "e") parsed += "\x1B"; + else if (c === "\"") parsed += "\""; + else if (c === "\\") parsed += "\\"; + else throw new TomlError("unrecognized escape sequence", { + toml: str, + ptr: i + }); + sliceStart = i + 1; + state = 0; + } + else if (c !== " " && c !== " ") { + if (state === 2) throw new TomlError("invalid escape: only line-ending whitespace may be escaped", { + toml: str, + ptr: sliceStart + }); + state = !isLiteral && c === "\\" ? 1 : 0; + sliceStart = i; + } + } + throw new TomlError("unfinished string", { + toml: str, + ptr + }); +} +function parseValue(value, toml, ptr, integersAsBigInt) { + if (value === "true") return true; + if (value === "false") return false; + if (value === "-inf") return -Infinity; + if (value === "inf" || value === "+inf") return Infinity; + if (value === "nan" || value === "+nan" || value === "-nan") return NaN; + if (value === "-0") return integersAsBigInt ? 0n : 0; + let isInt = INT_REGEX.test(value); + if (isInt || FLOAT_REGEX.test(value)) { + if (LEADING_ZERO.test(value)) throw new TomlError("leading zeroes are not allowed", { + toml, + ptr + }); + value = value.replace(/_/g, ""); + let numeric = +value; + if (isNaN(numeric)) throw new TomlError("invalid number", { + toml, + ptr + }); + if (isInt) { + if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) throw new TomlError("integer value cannot be represented losslessly", { + toml, + ptr + }); + if (isInt || integersAsBigInt === true) numeric = BigInt(value); + } + return numeric; + } + const date = new TomlDate(value); + if (!date.isValid()) throw new TomlError("invalid value", { + toml, + ptr + }); + return date; +} +//#endregion +//#region src/util.ts +function indexOfNewline(str, start = 0, end = str.length) { + let idx = str.indexOf("\n", start); + if (str[idx - 1] === "\r") idx--; + return idx <= end ? idx : -1; +} +function skipComment(str, ptr) { + for (let i = ptr; i < str.length; i++) { + let c = str[i]; + if (c === "\n") return i; + if (c === "\r" && str[i + 1] === "\n") return i + 1; + if (c < " " && c !== " " || c === "") throw new TomlError("control characters are not allowed in comments", { + toml: str, + ptr + }); + } + return str.length; +} +function skipVoid(str, ptr, banNewLines, banComments) { + let c; + while (1) { + while ((c = str[ptr]) === " " || c === " " || !banNewLines && (c === "\n" || c === "\r" && str[ptr + 1] === "\n")) ptr++; + if (banComments || c !== "#") break; + ptr = skipComment(str, ptr); + } + return ptr; +} +function skipUntil(str, ptr, sep, end, banNewLines = false) { + if (!end) { + ptr = indexOfNewline(str, ptr); + return ptr < 0 ? str.length : ptr; + } + for (let i = ptr; i < str.length; i++) { + let c = str[i]; + if (c === "#") i = indexOfNewline(str, i); + else if (c === sep) return i + 1; + else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) return i; + } + throw new TomlError("cannot find end of structure", { + toml: str, + ptr + }); +} +//#endregion +//#region src/extract.ts +function sliceAndTrimEndOf(str, startPtr, endPtr) { + let value = str.slice(startPtr, endPtr); + let commentIdx = value.indexOf("#"); + if (commentIdx > -1) { + skipComment(str, commentIdx); + value = value.slice(0, commentIdx); + } + return [value.trimEnd(), commentIdx]; +} +function extractValue(str, ptr, end, depth, integersAsBigInt) { + if (depth === 0) throw new TomlError("document contains excessively nested structures. aborting.", { + toml: str, + ptr + }); + let c = str[ptr]; + if (c === "[" || c === "{") { + let [value, endPtr] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt); + if (end) { + endPtr = skipVoid(str, endPtr); + if (str[endPtr] === ",") endPtr++; + else if (str[endPtr] !== end) throw new TomlError("expected comma or end of structure", { + toml: str, + ptr: endPtr + }); + } + return [value, endPtr]; + } + if (c === "\"" || c === "'") { + let [parsed, endPtr] = parseString(str, ptr); + if (end) { + endPtr = skipVoid(str, endPtr); + if (str[endPtr] && str[endPtr] !== "," && str[endPtr] !== end && str[endPtr] !== "\n" && str[endPtr] !== "\r") throw new TomlError("unexpected character encountered", { + toml: str, + ptr: endPtr + }); + if (str[endPtr] === ",") endPtr++; + } + return [parsed, endPtr]; + } + let endPtr = skipUntil(str, ptr, ",", end); + let slice = sliceAndTrimEndOf(str, ptr, endPtr - (str[endPtr - 1] === "," ? 1 : 0)); + if (!slice[0]) throw new TomlError("incomplete key-value declaration: no value specified", { + toml: str, + ptr + }); + if (end && slice[1] > -1) { + endPtr = skipVoid(str, ptr + slice[1]); + if (str[endPtr] === ",") endPtr++; + } + return [parseValue(slice[0], str, ptr, integersAsBigInt), endPtr]; +} +//#endregion +//#region src/struct.ts +let KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/; +function parseKey(str, ptr, end = "=") { + let dot = ptr - 1; + let parsed = []; + let endPtr = str.indexOf(end, ptr); + if (endPtr < 0) throw new TomlError("incomplete key-value: cannot find end of key", { + toml: str, + ptr + }); + do { + let c = str[ptr = ++dot]; + if (c !== " " && c !== " ") if (c === "\"" || c === "'") { + if (c === str[ptr + 1] && c === str[ptr + 2]) throw new TomlError("multiline strings are not allowed in keys", { + toml: str, + ptr + }); + let [part, eos] = parseString(str, ptr); + dot = str.indexOf(".", eos); + let strEnd = str.slice(eos, dot < 0 || dot > endPtr ? endPtr : dot); + let newLine = indexOfNewline(strEnd); + if (newLine > -1) throw new TomlError("newlines are not allowed in keys", { + toml: str, + ptr: ptr + dot + newLine + }); + if (strEnd.trimStart()) throw new TomlError("found extra tokens after the string part", { + toml: str, + ptr: eos + }); + if (endPtr < eos) { + endPtr = str.indexOf(end, eos); + if (endPtr < 0) throw new TomlError("incomplete key-value: cannot find end of key", { + toml: str, + ptr + }); + } + parsed.push(part); + } else { + dot = str.indexOf(".", ptr); + let part = str.slice(ptr, dot < 0 || dot > endPtr ? endPtr : dot); + if (!KEY_PART_RE.test(part)) throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", { + toml: str, + ptr + }); + parsed.push(part.trimEnd()); + } + } while (dot + 1 && dot < endPtr); + return [parsed, skipVoid(str, endPtr + 1, true, true)]; +} +function parseInlineTable(str, ptr, depth, integersAsBigInt) { + let res = {}; + let seen = /* @__PURE__ */ new Set(); + let c; + ptr++; + while ((c = str[ptr++]) !== "}" && c) if (c === ",") throw new TomlError("expected value, found comma", { + toml: str, + ptr: ptr - 1 + }); + else if (c === "#") ptr = skipComment(str, ptr); + else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") { + let k; + let t = res; + let hasOwn = false; + let [key, keyEndPtr] = parseKey(str, ptr - 1); + for (let i = 0; i < key.length; i++) { + if (i) t = hasOwn ? t[k] : t[k] = {}; + k = key[i]; + if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) throw new TomlError("trying to redefine an already defined value", { + toml: str, + ptr + }); + if (!hasOwn && k === "__proto__") Object.defineProperty(t, k, { + enumerable: true, + configurable: true, + writable: true + }); + } + if (hasOwn) throw new TomlError("trying to redefine an already defined value", { + toml: str, + ptr + }); + let [value, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1, integersAsBigInt); + seen.add(value); + t[k] = value; + ptr = valueEndPtr; + } + if (!c) throw new TomlError("unfinished table encountered", { + toml: str, + ptr + }); + return [res, ptr]; +} +function parseArray(str, ptr, depth, integersAsBigInt) { + let res = []; + let c; + ptr++; + while ((c = str[ptr++]) !== "]" && c) if (c === ",") throw new TomlError("expected value, found comma", { + toml: str, + ptr: ptr - 1 + }); + else if (c === "#") ptr = skipComment(str, ptr); + else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") { + let e = extractValue(str, ptr - 1, "]", depth - 1, integersAsBigInt); + res.push(e[0]); + ptr = e[1]; + } + if (!c) throw new TomlError("unfinished array encountered", { + toml: str, + ptr + }); + return [res, ptr]; +} +//#endregion +//#region src/parse.ts +function peekTable(key, table, meta, type) { + let t = table; + let m = meta; + let k; + let hasOwn = false; + let state; + for (let i = 0; i < key.length; i++) { + if (i) { + t = hasOwn ? t[k] : t[k] = {}; + m = (state = m[k]).c; + if (type === 0 && (state.t === 1 || state.t === 2)) return null; + if (state.t === 2) { + let l = t.length - 1; + t = t[l]; + m = m[l].c; + } + } + k = key[i]; + if ((hasOwn = Object.hasOwn(t, k)) && m[k]?.t === 0 && m[k]?.d) return null; + if (!hasOwn) { + if (k === "__proto__") { + Object.defineProperty(t, k, { + enumerable: true, + configurable: true, + writable: true + }); + Object.defineProperty(m, k, { + enumerable: true, + configurable: true, + writable: true + }); + } + m[k] = { + t: i < key.length - 1 && type === 2 ? 3 : type, + d: false, + i: 0, + c: {} + }; + } + } + state = m[k]; + if (state.t !== type && !(type === 1 && state.t === 3)) return null; + if (type === 2) { + if (!state.d) { + state.d = true; + t[k] = []; + } + t[k].push(t = {}); + state.c[state.i++] = state = { + t: 1, + d: false, + i: 0, + c: {} + }; + } + if (state.d) return null; + state.d = true; + if (type === 1) t = hasOwn ? t[k] : t[k] = {}; + else if (type === 0 && hasOwn) return null; + return [ + k, + t, + state.c + ]; +} +function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) { + let res = {}; + let meta = {}; + let tbl = res; + let m = meta; + for (let ptr = skipVoid(toml, 0); ptr < toml.length;) { + if (toml[ptr] === "[") { + let isTableArray = toml[++ptr] === "["; + let k = parseKey(toml, ptr += +isTableArray, "]"); + if (isTableArray) { + if (toml[k[1] - 1] !== "]") throw new TomlError("expected end of table declaration", { + toml, + ptr: k[1] - 1 + }); + k[1]++; + } + let p = peekTable(k[0], res, meta, isTableArray ? 2 : 1); + if (!p) throw new TomlError("trying to redefine an already defined table or value", { + toml, + ptr + }); + m = p[2]; + tbl = p[1]; + ptr = k[1]; + } else { + let k = parseKey(toml, ptr); + let p = peekTable(k[0], tbl, m, 0); + if (!p) throw new TomlError("trying to redefine an already defined table or value", { + toml, + ptr + }); + let v = extractValue(toml, k[1], void 0, maxDepth, integersAsBigInt); + p[1][p[0]] = v[0]; + ptr = v[1]; + } + ptr = skipVoid(toml, ptr, true); + if (toml[ptr] && toml[ptr] !== "\n" && toml[ptr] !== "\r") throw new TomlError("each key-value declaration must be followed by an end-of-line", { + toml, + ptr + }); + ptr = skipVoid(toml, ptr); + } + return res; +} +//#endregion +//#region src/stringify.ts +let BARE_KEY = /^[a-z0-9-_]+$/i; +function extendedTypeOf(obj) { + let type = typeof obj; + if (type === "object") { + if (Array.isArray(obj)) return "array"; + if (obj instanceof Date) return "date"; + } + return type; +} +function isArrayOfTables(obj) { + for (let i = 0; i < obj.length; i++) if (extendedTypeOf(obj[i]) !== "object") return false; + return obj.length != 0; +} +function formatString(s) { + return JSON.stringify(s).replace(/\x7f/g, "\\u007f"); +} +function stringifyValue(val, type, depth, numberAsFloat) { + if (depth === 0) throw new Error("Could not stringify the object: maximum object depth exceeded"); + if (type === "number") { + if (isNaN(val)) return "nan"; + if (val === Infinity) return "inf"; + if (val === -Infinity) return "-inf"; + if (Number.isInteger(val) && (numberAsFloat || !Number.isSafeInteger(val))) return val.toFixed(1); + return val.toString(); + } + if (type === "bigint" || type === "boolean") return val.toString(); + if (type === "string") return formatString(val); + if (type === "date") { + if (isNaN(val.getTime())) throw new TypeError("cannot serialize invalid date"); + return val.toISOString(); + } + if (type === "object") return stringifyInlineTable(val, depth, numberAsFloat); + if (type === "array") return stringifyArray(val, depth, numberAsFloat); +} +function stringifyInlineTable(obj, depth, numberAsFloat) { + let keys = Object.keys(obj); + if (keys.length === 0) return "{}"; + let res = "{ "; + for (let i = 0; i < keys.length; i++) { + let k = keys[i]; + if (i) res += ", "; + res += BARE_KEY.test(k) ? k : formatString(k); + res += " = "; + res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat); + } + return res + " }"; +} +function stringifyArray(array, depth, numberAsFloat) { + if (array.length === 0) return "[]"; + let res = "[ "; + for (let i = 0; i < array.length; i++) { + if (i) res += ", "; + if (array[i] === null || array[i] === void 0) throw new TypeError("arrays cannot contain null or undefined values"); + res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1, numberAsFloat); + } + return res + " ]"; +} +function stringifyArrayTable(array, key, depth, numberAsFloat) { + if (depth === 0) throw new Error("Could not stringify the object: maximum object depth exceeded"); + let res = ""; + for (let i = 0; i < array.length; i++) { + res += `${res && "\n"}[[${key}]]\n`; + res += stringifyTable(0, array[i], key, depth, numberAsFloat); + } + return res; +} +function stringifyTable(tableKey, obj, prefix, depth, numberAsFloat) { + if (depth === 0) throw new Error("Could not stringify the object: maximum object depth exceeded"); + let preamble = ""; + let tables = ""; + let keys = Object.keys(obj); + for (let i = 0; i < keys.length; i++) { + let k = keys[i]; + if (obj[k] !== null && obj[k] !== void 0) { + let type = extendedTypeOf(obj[k]); + if (type === "symbol" || type === "function") throw new TypeError(`cannot serialize values of type '${type}'`); + let key = BARE_KEY.test(k) ? k : formatString(k); + if (type === "array" && isArrayOfTables(obj[k])) tables += (tables && "\n") + stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat); + else if (type === "object") { + let tblKey = prefix ? `${prefix}.${key}` : key; + tables += (tables && "\n") + stringifyTable(tblKey, obj[k], tblKey, depth - 1, numberAsFloat); + } else { + preamble += key; + preamble += " = "; + preamble += stringifyValue(obj[k], type, depth, numberAsFloat); + preamble += "\n"; + } + } + } + if (tableKey && (preamble || !tables)) preamble = preamble ? `[${tableKey}]\n${preamble}` : `[${tableKey}]`; + return preamble && tables ? `${preamble}\n${tables}` : preamble || tables; +} +function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) { + if (extendedTypeOf(obj) !== "object") throw new TypeError("stringify can only be called with an object"); + let str = stringifyTable(0, obj, "", maxDepth, numbersAsFloat); + if (str[str.length - 1] !== "\n") return str + "\n"; + return str; +} +//#endregion +//#region src/index.ts +var src_default = { + parse, + stringify, + TomlDate, + TomlError +}; +//#endregion +exports.TomlDate = TomlDate; +exports.TomlError = TomlError; +exports["default"] = src_default; +exports.parse = parse; +exports.stringify = stringify; + +//# sourceMappingURL=index.cjs.map + +/***/ }), + /***/ 64012: /***/ ((module) => { diff --git a/dist/setup/index.js b/dist/setup/index.js index bb0a1e93..ca4973ad 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -58297,6 +58297,7 @@ exports.printEnvDetailsAndSetOutput = printEnvDetailsAndSetOutput; const core = __importStar(__nccwpck_require__(37484)); const exec = __importStar(__nccwpck_require__(95236)); const io = __importStar(__nccwpck_require__(94994)); +const smol_toml_1 = __nccwpck_require__(27106); const fs_1 = __importDefault(__nccwpck_require__(79896)); const path_1 = __importDefault(__nccwpck_require__(16928)); function getNodeVersionFromFile(versionFilePath) { @@ -58350,6 +58351,23 @@ function getNodeVersionFromFile(versionFilePath) { catch { core.info('Node version file is not JSON file'); } + // Try parsing the file as a mise `mise.toml` file. + try { + const manifest = (0, smol_toml_1.parse)(contents); + if (manifest?.tools?.node) { + const node = manifest.tools.node; + if (typeof node === 'object' && node?.version) { + return node.version; + } + if (typeof node === 'string') { + return node; + } + return null; + } + } + catch { + core.info('Node version file is not TOML file'); + } const found = contents.match(/^(?:node(js)?\s+)?v?(?[^\s]+)$/m); return found?.groups?.version ?? contents.trim(); } @@ -99818,6 +99836,721 @@ function randomUUID() { /***/ }), +/***/ 27106: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; +/*! +* Copyright (c) Squirrel Chat et al., All rights reserved. +* SPDX-License-Identifier: BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this +* list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the copyright holder nor the names of its contributors +* may be used to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +Object.defineProperties(exports, { + __esModule: { value: true }, + [Symbol.toStringTag]: { value: "Module" } +}); +//#region src/date.ts +let DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i; +var TomlDate = class TomlDate extends Date { + #hasDate = false; + #hasTime = false; + #offset = null; + constructor(date) { + let hasDate = true; + let hasTime = true; + let offset = "Z"; + if (typeof date === "string") { + let match = date.match(DATE_TIME_RE); + if (match) { + if (!match[1]) { + hasDate = false; + date = `0000-01-01T${date}`; + } + hasTime = !!match[2]; + hasTime && date[10] === " " && (date = date.replace(" ", "T")); + if (match[2] && +match[2] > 23) date = ""; + else { + offset = match[3] || null; + date = date.toUpperCase(); + if (!offset && hasTime) date += "Z"; + } + } else date = ""; + } + super(date); + if (!isNaN(this.getTime())) { + this.#hasDate = hasDate; + this.#hasTime = hasTime; + this.#offset = offset; + } + } + isDateTime() { + return this.#hasDate && this.#hasTime; + } + isLocal() { + return !this.#hasDate || !this.#hasTime || !this.#offset; + } + isDate() { + return this.#hasDate && !this.#hasTime; + } + isTime() { + return this.#hasTime && !this.#hasDate; + } + isValid() { + return this.#hasDate || this.#hasTime; + } + toISOString() { + let iso = super.toISOString(); + if (this.isDate()) return iso.slice(0, 10); + if (this.isTime()) return iso.slice(11, 23); + if (this.#offset === null) return iso.slice(0, -1); + if (this.#offset === "Z") return iso; + let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6); + offset = this.#offset[0] === "-" ? offset : -offset; + return (/* @__PURE__ */ new Date(this.getTime() - offset * 6e4)).toISOString().slice(0, -1) + this.#offset; + } + static wrapAsOffsetDateTime(jsDate, offset = "Z") { + let date = new TomlDate(jsDate); + date.#offset = offset; + return date; + } + static wrapAsLocalDateTime(jsDate) { + let date = new TomlDate(jsDate); + date.#offset = null; + return date; + } + static wrapAsLocalDate(jsDate) { + let date = new TomlDate(jsDate); + date.#hasTime = false; + date.#offset = null; + return date; + } + static wrapAsLocalTime(jsDate) { + let date = new TomlDate(jsDate); + date.#hasDate = false; + date.#offset = null; + return date; + } +}; +//#endregion +//#region src/error.ts +function getLineColFromPtr(string, ptr) { + let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g); + return [lines.length, lines.pop().length + 1]; +} +function makeCodeBlock(string, line, column) { + let lines = string.split(/\r\n|\n|\r/g); + let codeblock = ""; + let numberLen = (Math.log10(line + 1) | 0) + 1; + for (let i = line - 1; i <= line + 1; i++) { + let l = lines[i - 1]; + if (!l) continue; + codeblock += i.toString().padEnd(numberLen, " "); + codeblock += ": "; + codeblock += l; + codeblock += "\n"; + if (i === line) { + codeblock += " ".repeat(numberLen + column + 2); + codeblock += "^\n"; + } + } + return codeblock; +} +var TomlError = class extends Error { + line; + column; + codeblock; + constructor(message, options) { + const [line, column] = getLineColFromPtr(options.toml, options.ptr); + const codeblock = makeCodeBlock(options.toml, line, column); + super(`Invalid TOML document: ${message}\n\n${codeblock}`, options); + this.line = line; + this.column = column; + this.codeblock = codeblock; + } +}; +//#endregion +//#region src/primitive.ts +let INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/; +let FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/; +let LEADING_ZERO = /^[+-]?0[0-9_]/; +function parseString(str, ptr) { + let c = str[ptr++]; + let first = c; + let isLiteral = c === "'"; + let isMultiline = c === str[ptr] && c === str[ptr + 1]; + if (isMultiline) { + if (str[ptr += 2] === "\n") ptr++; + else if (str[ptr] === "\r" && str[ptr + 1] === "\n") ptr += 2; + } + let parsed = ""; + let sliceStart = ptr; + let state = 0; + for (let i = ptr; i < str.length; i++) { + c = str[i]; + if (isMultiline && (c === "\n" || c === "\r" && str[i + 1] === "\n")) state = state && 3; + else if (c < " " && c !== " " || c === "") throw new TomlError("control characters are not allowed in strings", { + toml: str, + ptr: i + }); + else if ((!state || state === 3) && c === first && (!isMultiline || str[i + 1] === first && str[i + 2] === first)) { + if (isMultiline) { + if (str[i + 3] === first) i++; + if (str[i + 3] === first) i++; + } + return [state ? parsed : parsed + str.slice(sliceStart, i), i + (isMultiline ? 3 : 1)]; + } else if (!state) { + if (!isLiteral && c === "\\") { + parsed += str.slice(sliceStart, sliceStart = i); + state = 1; + } + } else if (state === 1) if (c === "x" || c === "u" || c === "U") { + let value = 0; + let len = c === "x" ? 2 : c === "u" ? 4 : 8; + for (let j = 0; j < len; j++, i++) { + let hex = str.charCodeAt(i + 1); + let digit = hex >= 48 && hex <= 57 ? hex - 48 : hex >= 65 && hex <= 70 ? hex - 65 + 10 : hex >= 97 && hex <= 102 ? hex - 97 + 10 : -1; + if (digit < 0) throw new TomlError("invalid non-hex character in unicode escape", { + toml: str, + ptr: i + 1 + }); + value = value << 4 | digit; + } + if (value < 0 || value > 1114111 || value >= 55296 && value <= 57343) throw new TomlError("invalid unicode escape", { + toml: str, + ptr: i + }); + parsed += String.fromCodePoint(value); + sliceStart = i + 1; + state = 0; + } else if (c === " " || c === " ") state = 2; + else { + if (c === "b") parsed += "\b"; + else if (c === "t") parsed += " "; + else if (c === "n") parsed += "\n"; + else if (c === "f") parsed += "\f"; + else if (c === "r") parsed += "\r"; + else if (c === "e") parsed += "\x1B"; + else if (c === "\"") parsed += "\""; + else if (c === "\\") parsed += "\\"; + else throw new TomlError("unrecognized escape sequence", { + toml: str, + ptr: i + }); + sliceStart = i + 1; + state = 0; + } + else if (c !== " " && c !== " ") { + if (state === 2) throw new TomlError("invalid escape: only line-ending whitespace may be escaped", { + toml: str, + ptr: sliceStart + }); + state = !isLiteral && c === "\\" ? 1 : 0; + sliceStart = i; + } + } + throw new TomlError("unfinished string", { + toml: str, + ptr + }); +} +function parseValue(value, toml, ptr, integersAsBigInt) { + if (value === "true") return true; + if (value === "false") return false; + if (value === "-inf") return -Infinity; + if (value === "inf" || value === "+inf") return Infinity; + if (value === "nan" || value === "+nan" || value === "-nan") return NaN; + if (value === "-0") return integersAsBigInt ? 0n : 0; + let isInt = INT_REGEX.test(value); + if (isInt || FLOAT_REGEX.test(value)) { + if (LEADING_ZERO.test(value)) throw new TomlError("leading zeroes are not allowed", { + toml, + ptr + }); + value = value.replace(/_/g, ""); + let numeric = +value; + if (isNaN(numeric)) throw new TomlError("invalid number", { + toml, + ptr + }); + if (isInt) { + if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) throw new TomlError("integer value cannot be represented losslessly", { + toml, + ptr + }); + if (isInt || integersAsBigInt === true) numeric = BigInt(value); + } + return numeric; + } + const date = new TomlDate(value); + if (!date.isValid()) throw new TomlError("invalid value", { + toml, + ptr + }); + return date; +} +//#endregion +//#region src/util.ts +function indexOfNewline(str, start = 0, end = str.length) { + let idx = str.indexOf("\n", start); + if (str[idx - 1] === "\r") idx--; + return idx <= end ? idx : -1; +} +function skipComment(str, ptr) { + for (let i = ptr; i < str.length; i++) { + let c = str[i]; + if (c === "\n") return i; + if (c === "\r" && str[i + 1] === "\n") return i + 1; + if (c < " " && c !== " " || c === "") throw new TomlError("control characters are not allowed in comments", { + toml: str, + ptr + }); + } + return str.length; +} +function skipVoid(str, ptr, banNewLines, banComments) { + let c; + while (1) { + while ((c = str[ptr]) === " " || c === " " || !banNewLines && (c === "\n" || c === "\r" && str[ptr + 1] === "\n")) ptr++; + if (banComments || c !== "#") break; + ptr = skipComment(str, ptr); + } + return ptr; +} +function skipUntil(str, ptr, sep, end, banNewLines = false) { + if (!end) { + ptr = indexOfNewline(str, ptr); + return ptr < 0 ? str.length : ptr; + } + for (let i = ptr; i < str.length; i++) { + let c = str[i]; + if (c === "#") i = indexOfNewline(str, i); + else if (c === sep) return i + 1; + else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) return i; + } + throw new TomlError("cannot find end of structure", { + toml: str, + ptr + }); +} +//#endregion +//#region src/extract.ts +function sliceAndTrimEndOf(str, startPtr, endPtr) { + let value = str.slice(startPtr, endPtr); + let commentIdx = value.indexOf("#"); + if (commentIdx > -1) { + skipComment(str, commentIdx); + value = value.slice(0, commentIdx); + } + return [value.trimEnd(), commentIdx]; +} +function extractValue(str, ptr, end, depth, integersAsBigInt) { + if (depth === 0) throw new TomlError("document contains excessively nested structures. aborting.", { + toml: str, + ptr + }); + let c = str[ptr]; + if (c === "[" || c === "{") { + let [value, endPtr] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt); + if (end) { + endPtr = skipVoid(str, endPtr); + if (str[endPtr] === ",") endPtr++; + else if (str[endPtr] !== end) throw new TomlError("expected comma or end of structure", { + toml: str, + ptr: endPtr + }); + } + return [value, endPtr]; + } + if (c === "\"" || c === "'") { + let [parsed, endPtr] = parseString(str, ptr); + if (end) { + endPtr = skipVoid(str, endPtr); + if (str[endPtr] && str[endPtr] !== "," && str[endPtr] !== end && str[endPtr] !== "\n" && str[endPtr] !== "\r") throw new TomlError("unexpected character encountered", { + toml: str, + ptr: endPtr + }); + if (str[endPtr] === ",") endPtr++; + } + return [parsed, endPtr]; + } + let endPtr = skipUntil(str, ptr, ",", end); + let slice = sliceAndTrimEndOf(str, ptr, endPtr - (str[endPtr - 1] === "," ? 1 : 0)); + if (!slice[0]) throw new TomlError("incomplete key-value declaration: no value specified", { + toml: str, + ptr + }); + if (end && slice[1] > -1) { + endPtr = skipVoid(str, ptr + slice[1]); + if (str[endPtr] === ",") endPtr++; + } + return [parseValue(slice[0], str, ptr, integersAsBigInt), endPtr]; +} +//#endregion +//#region src/struct.ts +let KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/; +function parseKey(str, ptr, end = "=") { + let dot = ptr - 1; + let parsed = []; + let endPtr = str.indexOf(end, ptr); + if (endPtr < 0) throw new TomlError("incomplete key-value: cannot find end of key", { + toml: str, + ptr + }); + do { + let c = str[ptr = ++dot]; + if (c !== " " && c !== " ") if (c === "\"" || c === "'") { + if (c === str[ptr + 1] && c === str[ptr + 2]) throw new TomlError("multiline strings are not allowed in keys", { + toml: str, + ptr + }); + let [part, eos] = parseString(str, ptr); + dot = str.indexOf(".", eos); + let strEnd = str.slice(eos, dot < 0 || dot > endPtr ? endPtr : dot); + let newLine = indexOfNewline(strEnd); + if (newLine > -1) throw new TomlError("newlines are not allowed in keys", { + toml: str, + ptr: ptr + dot + newLine + }); + if (strEnd.trimStart()) throw new TomlError("found extra tokens after the string part", { + toml: str, + ptr: eos + }); + if (endPtr < eos) { + endPtr = str.indexOf(end, eos); + if (endPtr < 0) throw new TomlError("incomplete key-value: cannot find end of key", { + toml: str, + ptr + }); + } + parsed.push(part); + } else { + dot = str.indexOf(".", ptr); + let part = str.slice(ptr, dot < 0 || dot > endPtr ? endPtr : dot); + if (!KEY_PART_RE.test(part)) throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", { + toml: str, + ptr + }); + parsed.push(part.trimEnd()); + } + } while (dot + 1 && dot < endPtr); + return [parsed, skipVoid(str, endPtr + 1, true, true)]; +} +function parseInlineTable(str, ptr, depth, integersAsBigInt) { + let res = {}; + let seen = /* @__PURE__ */ new Set(); + let c; + ptr++; + while ((c = str[ptr++]) !== "}" && c) if (c === ",") throw new TomlError("expected value, found comma", { + toml: str, + ptr: ptr - 1 + }); + else if (c === "#") ptr = skipComment(str, ptr); + else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") { + let k; + let t = res; + let hasOwn = false; + let [key, keyEndPtr] = parseKey(str, ptr - 1); + for (let i = 0; i < key.length; i++) { + if (i) t = hasOwn ? t[k] : t[k] = {}; + k = key[i]; + if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) throw new TomlError("trying to redefine an already defined value", { + toml: str, + ptr + }); + if (!hasOwn && k === "__proto__") Object.defineProperty(t, k, { + enumerable: true, + configurable: true, + writable: true + }); + } + if (hasOwn) throw new TomlError("trying to redefine an already defined value", { + toml: str, + ptr + }); + let [value, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1, integersAsBigInt); + seen.add(value); + t[k] = value; + ptr = valueEndPtr; + } + if (!c) throw new TomlError("unfinished table encountered", { + toml: str, + ptr + }); + return [res, ptr]; +} +function parseArray(str, ptr, depth, integersAsBigInt) { + let res = []; + let c; + ptr++; + while ((c = str[ptr++]) !== "]" && c) if (c === ",") throw new TomlError("expected value, found comma", { + toml: str, + ptr: ptr - 1 + }); + else if (c === "#") ptr = skipComment(str, ptr); + else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") { + let e = extractValue(str, ptr - 1, "]", depth - 1, integersAsBigInt); + res.push(e[0]); + ptr = e[1]; + } + if (!c) throw new TomlError("unfinished array encountered", { + toml: str, + ptr + }); + return [res, ptr]; +} +//#endregion +//#region src/parse.ts +function peekTable(key, table, meta, type) { + let t = table; + let m = meta; + let k; + let hasOwn = false; + let state; + for (let i = 0; i < key.length; i++) { + if (i) { + t = hasOwn ? t[k] : t[k] = {}; + m = (state = m[k]).c; + if (type === 0 && (state.t === 1 || state.t === 2)) return null; + if (state.t === 2) { + let l = t.length - 1; + t = t[l]; + m = m[l].c; + } + } + k = key[i]; + if ((hasOwn = Object.hasOwn(t, k)) && m[k]?.t === 0 && m[k]?.d) return null; + if (!hasOwn) { + if (k === "__proto__") { + Object.defineProperty(t, k, { + enumerable: true, + configurable: true, + writable: true + }); + Object.defineProperty(m, k, { + enumerable: true, + configurable: true, + writable: true + }); + } + m[k] = { + t: i < key.length - 1 && type === 2 ? 3 : type, + d: false, + i: 0, + c: {} + }; + } + } + state = m[k]; + if (state.t !== type && !(type === 1 && state.t === 3)) return null; + if (type === 2) { + if (!state.d) { + state.d = true; + t[k] = []; + } + t[k].push(t = {}); + state.c[state.i++] = state = { + t: 1, + d: false, + i: 0, + c: {} + }; + } + if (state.d) return null; + state.d = true; + if (type === 1) t = hasOwn ? t[k] : t[k] = {}; + else if (type === 0 && hasOwn) return null; + return [ + k, + t, + state.c + ]; +} +function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) { + let res = {}; + let meta = {}; + let tbl = res; + let m = meta; + for (let ptr = skipVoid(toml, 0); ptr < toml.length;) { + if (toml[ptr] === "[") { + let isTableArray = toml[++ptr] === "["; + let k = parseKey(toml, ptr += +isTableArray, "]"); + if (isTableArray) { + if (toml[k[1] - 1] !== "]") throw new TomlError("expected end of table declaration", { + toml, + ptr: k[1] - 1 + }); + k[1]++; + } + let p = peekTable(k[0], res, meta, isTableArray ? 2 : 1); + if (!p) throw new TomlError("trying to redefine an already defined table or value", { + toml, + ptr + }); + m = p[2]; + tbl = p[1]; + ptr = k[1]; + } else { + let k = parseKey(toml, ptr); + let p = peekTable(k[0], tbl, m, 0); + if (!p) throw new TomlError("trying to redefine an already defined table or value", { + toml, + ptr + }); + let v = extractValue(toml, k[1], void 0, maxDepth, integersAsBigInt); + p[1][p[0]] = v[0]; + ptr = v[1]; + } + ptr = skipVoid(toml, ptr, true); + if (toml[ptr] && toml[ptr] !== "\n" && toml[ptr] !== "\r") throw new TomlError("each key-value declaration must be followed by an end-of-line", { + toml, + ptr + }); + ptr = skipVoid(toml, ptr); + } + return res; +} +//#endregion +//#region src/stringify.ts +let BARE_KEY = /^[a-z0-9-_]+$/i; +function extendedTypeOf(obj) { + let type = typeof obj; + if (type === "object") { + if (Array.isArray(obj)) return "array"; + if (obj instanceof Date) return "date"; + } + return type; +} +function isArrayOfTables(obj) { + for (let i = 0; i < obj.length; i++) if (extendedTypeOf(obj[i]) !== "object") return false; + return obj.length != 0; +} +function formatString(s) { + return JSON.stringify(s).replace(/\x7f/g, "\\u007f"); +} +function stringifyValue(val, type, depth, numberAsFloat) { + if (depth === 0) throw new Error("Could not stringify the object: maximum object depth exceeded"); + if (type === "number") { + if (isNaN(val)) return "nan"; + if (val === Infinity) return "inf"; + if (val === -Infinity) return "-inf"; + if (Number.isInteger(val) && (numberAsFloat || !Number.isSafeInteger(val))) return val.toFixed(1); + return val.toString(); + } + if (type === "bigint" || type === "boolean") return val.toString(); + if (type === "string") return formatString(val); + if (type === "date") { + if (isNaN(val.getTime())) throw new TypeError("cannot serialize invalid date"); + return val.toISOString(); + } + if (type === "object") return stringifyInlineTable(val, depth, numberAsFloat); + if (type === "array") return stringifyArray(val, depth, numberAsFloat); +} +function stringifyInlineTable(obj, depth, numberAsFloat) { + let keys = Object.keys(obj); + if (keys.length === 0) return "{}"; + let res = "{ "; + for (let i = 0; i < keys.length; i++) { + let k = keys[i]; + if (i) res += ", "; + res += BARE_KEY.test(k) ? k : formatString(k); + res += " = "; + res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat); + } + return res + " }"; +} +function stringifyArray(array, depth, numberAsFloat) { + if (array.length === 0) return "[]"; + let res = "[ "; + for (let i = 0; i < array.length; i++) { + if (i) res += ", "; + if (array[i] === null || array[i] === void 0) throw new TypeError("arrays cannot contain null or undefined values"); + res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1, numberAsFloat); + } + return res + " ]"; +} +function stringifyArrayTable(array, key, depth, numberAsFloat) { + if (depth === 0) throw new Error("Could not stringify the object: maximum object depth exceeded"); + let res = ""; + for (let i = 0; i < array.length; i++) { + res += `${res && "\n"}[[${key}]]\n`; + res += stringifyTable(0, array[i], key, depth, numberAsFloat); + } + return res; +} +function stringifyTable(tableKey, obj, prefix, depth, numberAsFloat) { + if (depth === 0) throw new Error("Could not stringify the object: maximum object depth exceeded"); + let preamble = ""; + let tables = ""; + let keys = Object.keys(obj); + for (let i = 0; i < keys.length; i++) { + let k = keys[i]; + if (obj[k] !== null && obj[k] !== void 0) { + let type = extendedTypeOf(obj[k]); + if (type === "symbol" || type === "function") throw new TypeError(`cannot serialize values of type '${type}'`); + let key = BARE_KEY.test(k) ? k : formatString(k); + if (type === "array" && isArrayOfTables(obj[k])) tables += (tables && "\n") + stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat); + else if (type === "object") { + let tblKey = prefix ? `${prefix}.${key}` : key; + tables += (tables && "\n") + stringifyTable(tblKey, obj[k], tblKey, depth - 1, numberAsFloat); + } else { + preamble += key; + preamble += " = "; + preamble += stringifyValue(obj[k], type, depth, numberAsFloat); + preamble += "\n"; + } + } + } + if (tableKey && (preamble || !tables)) preamble = preamble ? `[${tableKey}]\n${preamble}` : `[${tableKey}]`; + return preamble && tables ? `${preamble}\n${tables}` : preamble || tables; +} +function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) { + if (extendedTypeOf(obj) !== "object") throw new TypeError("stringify can only be called with an object"); + let str = stringifyTable(0, obj, "", maxDepth, numbersAsFloat); + if (str[str.length - 1] !== "\n") return str + "\n"; + return str; +} +//#endregion +//#region src/index.ts +var src_default = { + parse, + stringify, + TomlDate, + TomlError +}; +//#endregion +exports.TomlDate = TomlDate; +exports.TomlError = TomlError; +exports["default"] = src_default; +exports.parse = parse; +exports.stringify = stringify; + +//# sourceMappingURL=index.cjs.map + +/***/ }), + /***/ 64012: /***/ ((module) => { diff --git a/package-lock.json b/package-lock.json index e7b05b2e..4ae72e5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,8 @@ "@actions/http-client": "^3.0.2", "@actions/io": "^2.0.0", "@actions/tool-cache": "^3.0.1", - "semver": "^7.6.3" + "semver": "^7.6.3", + "smol-toml": "^1.6.1" }, "devDependencies": { "@types/jest": "^29.5.14", @@ -5467,6 +5468,18 @@ "node": ">=8" } }, + "node_modules/smol-toml": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.0.tgz", + "integrity": "sha512-aqVvWoyO21L23mb+drl4RmMXbf6N7FdHjAhTRA9ZBL7apWBgfWC16KjrASI+1p9GAroljyMHj6fK67i0UiTNvQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/package.json b/package.json index c2157866..f0f4af06 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,8 @@ "@actions/http-client": "^3.0.2", "@actions/io": "^2.0.0", "@actions/tool-cache": "^3.0.1", - "semver": "^7.6.3" + "semver": "^7.6.3", + "smol-toml": "^1.6.1" }, "devDependencies": { "@types/jest": "^29.5.14", diff --git a/src/util.ts b/src/util.ts index dd34f7e5..4c421586 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,6 +1,7 @@ import * as core from '@actions/core'; import * as exec from '@actions/exec'; import * as io from '@actions/io'; +import {parse} from 'smol-toml'; import fs from 'fs'; import path from 'path'; @@ -68,6 +69,26 @@ export function getNodeVersionFromFile(versionFilePath: string): string | null { core.info('Node version file is not JSON file'); } + // Try parsing the file as a mise `mise.toml` file. + try { + const manifest: Record = parse(contents); + if (manifest?.tools?.node) { + const node = manifest.tools.node; + + if (typeof node === 'object' && node?.version) { + return node.version; + } + + if (typeof node === 'string') { + return node; + } + + return null; + } + } catch { + core.info('Node version file is not TOML file'); + } + const found = contents.match(/^(?:node(js)?\s+)?v?(?[^\s]+)$/m); return found?.groups?.version ?? contents.trim(); }