diff --git a/Dockerfile b/Dockerfile index f3bed18a..159305ae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,6 +7,6 @@ ENV DENO_NO_UPDATE_CHECK=1 RUN apt-get --assume-yes update && apt-get --assume-yes dist-upgrade && apt-get --assume-yes install apt-utils COPY --from=denoland/deno:bin-1.46.3 /deno /opt/denoland/deno/deno RUN chmod +x /opt/denoland/deno/deno && ln -s /opt/denoland/deno/deno /usr/bin/deno -COPY _color_namespace_list.ts _fswalk.ts _payload.ts _random_integer.ts deno.jsonc mod.ts ${APP_ROOT}/ +COPY _color_namespace_list.ts _fswalk.ts _parameter.ts _payload.ts _random_integer.ts deno.jsonc mod.ts ${APP_ROOT}/ RUN cd $APP_ROOT && deno vendor mod.ts CMD deno run --allow-env --allow-net=discord.com --allow-read --allow-write --import-map=$APP_ROOT/vendor/import_map.json --no-config $APP_ROOT/mod.ts diff --git a/_parameter.ts b/_parameter.ts new file mode 100644 index 00000000..63b588f7 --- /dev/null +++ b/_parameter.ts @@ -0,0 +1,90 @@ +import { isStringSingleLine } from "ISSTRINGSINGLELINE"; +export interface GitHubActionsInputOptions { + defaultValue?: T; + /** + * Whether the input is require. + * @default false + */ + require?: boolean; +} +/** + * Get the raw value of an input. + * + * > **🛡️ Require Permission** + * > + * > - Environment Variable (`allow-env`) + * @param {string} key Key of the input. + * @returns {string} Raw value of the input. + */ +function getInputRaw(key: string): string { + if (!isStringSingleLine(key)) { + throw new SyntaxError(`\`${key}\` is not a valid GitHub Actions input key!`); + } + return Deno.env.get(`INPUT_${key.replaceAll(" ", "_").toUpperCase()}`) ?? ""; +} +/** + * Get the value of an input. + * + * > **🛡️ Require Permission** + * > + * > - Environment Variable (`allow-env`) + * @param {string} key Key of the input. + * @param {GitHubActionsInputOptions} [options={}] Options. + * @returns {string} Value of the input. + */ +export function getInput(key: string, options: GitHubActionsInputOptions = {}): string { + const value: string = getInputRaw(key); + if (value.length === 0) { + if (options.require) { + throw new ReferenceError(`Input \`${key}\` is not defined!`); + } + return options.defaultValue ?? ""; + } + return value; +} +/** + * Get the boolean value of an input. + * + * > **🛡️ Require Permission** + * > + * > - Environment Variable (`allow-env`) + * @param {string} key Key of the input. + * @param {GitHubActionsInputOptions} [options={}] Options. + * @returns {boolean} Boolean value of the input. + */ +export function getInputBoolean(key: string, options: GitHubActionsInputOptions = {}): boolean { + const value: string = getInputRaw(key); + if (value.length === 0) { + if (options.require) { + throw new ReferenceError(`Input \`${key}\` is not defined!`); + } + return options.defaultValue ?? false; + } + if (/^[Ff]alse$|^FALSE$/.test(value)) { + return false; + } + if (/^[Tt]rue$|^TRUE$/.test(value)) { + return true; + } + throw new SyntaxError(`\`${value}\` (input \`${key}\`) is not a valid boolean!`); +} +/** + * Get the number value of an input. + * + * > **🛡️ Require Permission** + * > + * > - Environment Variable (`allow-env`) + * @param {string} key Key of the input. + * @param {GitHubActionsInputOptions} [options={}] Options. + * @returns {number} Number value of the input. + */ +export function getInputNumber(key: string, options: GitHubActionsInputOptions = {}): number { + const value: string = getInputRaw(key); + if (value.length === 0) { + if (options.require) { + throw new ReferenceError(`Input \`${key}\` is not defined!`); + } + return options.defaultValue ?? 0; + } + return Number(value); +} diff --git a/_payload.ts b/_payload.ts index 62be9f0b..7255ed3d 100644 --- a/_payload.ts +++ b/_payload.ts @@ -68,6 +68,9 @@ export function resolveContent(content: string, contentLinksNoEmbed: string[] = return contentFmt; } export function resolveEmbeds(embeds: unknown, truncator?: StringTruncator): JSONArray | undefined { + if (embeds === null) { + return undefined; + } if (!isJSONArray(embeds)) { throw new TypeError(`Input \`embeds\` is not a valid Discord embeds!`); } @@ -466,7 +469,7 @@ export function resolveMentionsUser(users: string[]): string[] | undefined { export interface ResolvePollParameters { allowMultiSelect: boolean; answers: unknown; - duration?: number; + duration: number; question: string; } export function resolvePoll({ @@ -559,7 +562,7 @@ export function resolvePoll({ if (question.length > thresholdPollQuestion) { throw new SyntaxError(`Input \`poll.question.text\` must not longer than ${thresholdPollQuestion} characters (current ${question.length})!`); } - if (typeof duration !== "undefined" && !(Number.isSafeInteger(duration) && duration >= 1 && duration <= thresholdPollDuration)) { + if (duration !== -1 && !(Number.isSafeInteger(duration) && duration >= 1 && duration <= thresholdPollDuration)) { throw new TypeError(`Input \`poll.duration\` is not a number which is integer and between 1 and ${thresholdPollDuration}!`); } const result: JSONObject = { @@ -567,7 +570,7 @@ export function resolvePoll({ answers: answersFmt, allow_multiselect: allowMultiSelect }; - if (typeof duration !== "undefined") { + if (duration !== -1) { result.duration = duration; } return result; diff --git a/deno.jsonc b/deno.jsonc index 3b8ef15e..3569e09d 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -9,18 +9,19 @@ "useTabs": true }, "imports": { - "COLOR": "https://esm.sh/color@^4.2.3", - "COLORNAMESPACELISTCOMMUNITY": "https://unpkg.com/color-name-list@^10.25.1/dist/colornames.esm.js", - "EXFETCH": "jsr:@hugoalh/exfetch@^0.5.1", - "GHACTIONS": "jsr:@hugoalh/github-actions-core@^0.2.1", - "ISJSON": "jsr:@hugoalh/is-json@^1.0.2", - "REGEXPURL": "https://esm.sh/url-regex-safe@^4.0.0", - "STD/assert": "jsr:@std/assert@^1.0.4", - "STD/fs": "jsr:@std/fs@^1.0.3", - "STD/media-types": "jsr:@std/media-types@^1.0.3", - "STD/path": "jsr:@std/path@^1.0.4", - "STD/yaml": "jsr:@std/yaml@^1.0.5", - "STRINGOVERFLOW": "jsr:@hugoalh/string-overflow@^2.0.3" + "COLOR": "npm:color@4.2.3", + "COLORNAMESPACELISTCOMMUNITY": "npm:color-name-list@10.25.1/dist/colornames.esm.js", + "EXFETCH": "jsr:@hugoalh/exfetch@0.5.1", + "GHACTIONS": "jsr:@hugoalh/github-actions-core@0.2.1", + "ISJSON": "jsr:@hugoalh/is-json@1.0.2", + "ISSTRINGSINGLELINE":"jsr:@hugoalh/is-string-singleline@1.0.0", + "REGEXPURL": "npm:url-regex-safe@4.0.0", + "STD/assert": "jsr:@std/assert@1.0.4", + "STD/fs": "jsr:@std/fs@1.0.3", + "STD/media-types": "jsr:@std/media-types@1.0.3", + "STD/path": "jsr:@std/path@1.0.4", + "STD/yaml": "jsr:@std/yaml@1.0.5", + "STRINGOVERFLOW": "jsr:@hugoalh/string-overflow@2.0.3" }, "lint": { "rules": { diff --git a/mod.ts b/mod.ts index 03a1428e..e2ba2116 100644 --- a/mod.ts +++ b/mod.ts @@ -7,19 +7,18 @@ import { writeDebug, writeError } from "GHACTIONS/log"; -import { - getInput, - getInputBoolean, - getInputNumber, - getInputRaw, - setOutput -} from "GHACTIONS/parameter"; +import { setOutput } from "GHACTIONS/parameter"; import type { JSONArray, JSONObject, } from "ISJSON"; import { parse as yamlParse } from "STD/yaml/parse"; import { StringTruncator } from "STRINGOVERFLOW"; +import { + getInput, + getInputBoolean, + getInputNumber +} from "./_parameter.ts"; import { resolveContent, resolveEmbeds, @@ -45,31 +44,31 @@ writeDebug(`Environment Variables:\n${Object.entries(Deno.env.toObject()).map(([ return `${key} = ${value}`; }).join("\n")}`); try { - const truncateEnable: boolean = (typeof getInputRaw("truncate_enable") === "undefined") ? true : getInputBoolean("truncate_enable"); + const truncateEnable: boolean = getInputBoolean("truncate_enable", { defaultValue: true }); const stringTruncator: StringTruncator | undefined = truncateEnable ? new StringTruncator(128, { - ellipsisMark: getInputRaw("truncate_ellipsis") ?? "...", + ellipsisMark: getInput("truncate_ellipsis", { defaultValue: "..." }), //@ts-ignore Validate by package. - ellipsisPosition: getInputRaw("truncate_position") ?? "end" + ellipsisPosition: getInput("truncate_position", { defaultValue: "end" }) }) : undefined; const key: string = resolveKey(getInput("key", { require: true })); addSecretMask(key); const username: string | undefined = resolveUsername(getInput("username"), stringTruncator); - const avatarURL: string | undefined = getInputRaw("avatar_url"); + const avatarURL: string | undefined = getInput("avatar_url"); const content: string | undefined = resolveContent(getInput("content"), getInput("content_links_no_embed").split(splitterNewLine).filter((value: string): boolean => { return (value.length > 0); }), stringTruncator); - const embeds: JSONArray | undefined = resolveEmbeds(yamlParse(getInput("embeds")) ?? [], stringTruncator); + const embeds: JSONArray | undefined = resolveEmbeds(yamlParse(getInput("embeds")), stringTruncator); const poll: JSONObject | undefined = resolvePoll({ - allowMultiSelect: getInputBoolean("poll_allow_multiselect"), + allowMultiSelect: getInputBoolean("poll_allow_multiselect", { defaultValue: false }), answers: yamlParse(getInput("poll_answers")), - duration: (typeof getInputRaw("poll_duration") === "undefined") ? undefined : getInputNumber("poll_duration"), + duration: getInputNumber("poll_duration", { defaultValue: -1 }), question: getInput("poll_question") }); const files: FormData | undefined = await resolveFiles(getInput("files").split(splitterNewLine).map((file: string) => { return file.trim(); }).filter((file: string): boolean => { return (file.length > 0); - }), (typeof getInputRaw("files_glob") === "undefined") ? true : getInputBoolean("files_glob")); + }), getInputBoolean("files_glob", { defaultValue: true })); const allowedMentionsParse: string[] = resolveMentionsType(getInput("allowed_mentions_parse").split(splitterCommonDelimiter).map((value: string): string => { return value.trim(); }).filter((value: string): boolean => { @@ -93,8 +92,8 @@ try { }).filter((value: string): boolean => { return (value.length > 0); })); - const notification: boolean = (typeof getInputRaw("notification") === "undefined") ? true : getInputBoolean("notification"); - const wait: boolean = (typeof getInputRaw("wait") === "undefined") ? true : getInputBoolean("wait"); + const notification: boolean = getInputBoolean("notification", { defaultValue: true }); + const wait: boolean = getInputBoolean("wait", { defaultValue: true }); if ( (typeof content === "undefined" && typeof embeds === "undefined" && typeof files === "undefined" && typeof poll === "undefined") || ((