diff --git a/.gitignore b/.gitignore index 57451200..c2a1542e 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,5 @@ jspm_packages /.yarn_home/ .idea + +/keycloak_theme_email \ No newline at end of file diff --git a/package.json b/package.json index fccc1cd6..56e76092 100755 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ }, "bin": { "build-keycloak-theme": "dist/bin/build-keycloak-theme/index.js", + "create-keycloak-theme-email-directory": "dist/bin/create-keycloak-theme-email-directory.js", "download-builtin-keycloak-theme": "dist/bin/download-builtin-keycloak-theme.js" }, "lint-staged": { @@ -60,7 +61,7 @@ }, "devDependencies": { "@emotion/react": "^11.4.1", - "@types/node": "^10.0.0", + "@types/node": "^17.0.25", "@types/react": "^17.0.0", "copyfiles": "^2.4.1", "husky": "^4.3.8", @@ -72,14 +73,16 @@ "typescript": "^4.2.3" }, "dependencies": { + "@octokit/rest": "^18.12.0", "cheerio": "^1.0.0-rc.5", + "cli-select": "^1.1.2", "evt": "2.0.0-beta.39", "minimal-polyfills": "^2.2.1", "path-browserify": "^1.0.1", + "powerhooks": "^0.14.0", "react-markdown": "^5.0.3", "scripting-tools": "^0.19.13", "tsafe": "^0.9.0", - "tss-react": "^3.5.2", - "powerhooks": "^0.14.0" + "tss-react": "^3.5.2" } } diff --git a/src/bin/build-keycloak-theme/build-keycloak-theme.ts b/src/bin/build-keycloak-theme/build-keycloak-theme.ts index 8400a594..61176cde 100644 --- a/src/bin/build-keycloak-theme/build-keycloak-theme.ts +++ b/src/bin/build-keycloak-theme/build-keycloak-theme.ts @@ -19,6 +19,7 @@ const doUseExternalAssets = process.argv[2]?.toLowerCase() === "--external-asset const parsedPackageJson: ParsedPackageJson = require(pathJoin(reactProjectDirPath, "package.json")); export const keycloakThemeBuildingDirPath = pathJoin(reactProjectDirPath, "build_keycloak"); +export const keycloakThemeEmailDirPath = pathJoin(keycloakThemeBuildingDirPath, "..", "keycloak_theme_email"); function sanitizeThemeName(name: string) { return name @@ -34,8 +35,9 @@ export function main() { const extraThemeProperties: string[] = (parsedPackageJson as any)["keycloakify"]?.["extraThemeProperties"] ?? []; const themeName = sanitizeThemeName(parsedPackageJson.name); - generateKeycloakThemeResources({ + const { doBundleEmailTemplate } = generateKeycloakThemeResources({ keycloakThemeBuildingDirPath, + keycloakThemeEmailDirPath, "reactAppBuildDirPath": pathJoin(reactProjectDirPath, "build"), themeName, ...(() => { @@ -78,10 +80,11 @@ export function main() { }); const { jarFilePath } = generateJavaStackFiles({ - version: parsedPackageJson.version, + "version": parsedPackageJson.version, themeName, - homepage: parsedPackageJson.homepage, + "homepage": parsedPackageJson.homepage, keycloakThemeBuildingDirPath, + doBundleEmailTemplate, }); child_process.execSync("mvn package", { diff --git a/src/bin/build-keycloak-theme/generateJavaStackFiles.ts b/src/bin/build-keycloak-theme/generateJavaStackFiles.ts index 117d6e75..b0f56946 100644 --- a/src/bin/build-keycloak-theme/generateJavaStackFiles.ts +++ b/src/bin/build-keycloak-theme/generateJavaStackFiles.ts @@ -2,10 +2,16 @@ import * as url from "url"; import * as fs from "fs"; import { join as pathJoin, dirname as pathDirname } from "path"; -export function generateJavaStackFiles(params: { version: string; themeName: string; homepage?: string; keycloakThemeBuildingDirPath: string }): { +export function generateJavaStackFiles(params: { + version: string; + themeName: string; + homepage?: string; + keycloakThemeBuildingDirPath: string; + doBundleEmailTemplate: boolean; +}): { jarFilePath: string; } { - const { themeName, version, homepage, keycloakThemeBuildingDirPath } = params; + const { themeName, version, homepage, keycloakThemeBuildingDirPath, doBundleEmailTemplate } = params; { const { pomFileCode } = (function generatePomFileCode(): { @@ -63,7 +69,7 @@ export function generateJavaStackFiles(params: { version: string; themeName: str "themes": [ { "name": themeName, - "types": ["login"], + "types": ["login", ...(doBundleEmailTemplate ? ["email"] : [])], }, ], }, diff --git a/src/bin/build-keycloak-theme/generateKeycloakThemeResources.ts b/src/bin/build-keycloak-theme/generateKeycloakThemeResources.ts index aff511a4..e89299b1 100644 --- a/src/bin/build-keycloak-theme/generateKeycloakThemeResources.ts +++ b/src/bin/build-keycloak-theme/generateKeycloakThemeResources.ts @@ -12,17 +12,19 @@ export function generateKeycloakThemeResources(params: { themeName: string; reactAppBuildDirPath: string; keycloakThemeBuildingDirPath: string; + keycloakThemeEmailDirPath: string; urlPathname: string; //If urlOrigin is not undefined then it means --externals-assets urlOrigin: undefined | string; extraPagesId: string[]; extraThemeProperties: string[]; keycloakVersion: string; -}) { +}): { doBundleEmailTemplate: boolean } { const { themeName, reactAppBuildDirPath, keycloakThemeBuildingDirPath, + keycloakThemeEmailDirPath, urlPathname, urlOrigin, extraPagesId, @@ -79,6 +81,28 @@ export function generateKeycloakThemeResources(params: { }, }); + let doBundleEmailTemplate: boolean; + + email: { + if (!fs.existsSync(keycloakThemeEmailDirPath)) { + console.log( + [ + `Not bundling email template because ${pathBasename(keycloakThemeEmailDirPath)} does not exist`, + `To start customizing the email template, run: 👉 npx create-keycloak-theme-email-directory 👈`, + ].join("\n"), + ); + doBundleEmailTemplate = false; + break email; + } + + doBundleEmailTemplate = true; + + transformCodebase({ + "srcDirPath": keycloakThemeEmailDirPath, + "destDirPath": pathJoin(themeDirPath, "..", "email"), + }); + } + const { generateFtlFilesCode } = generateFtlFilesCodeFactory({ "cssGlobalsToDefine": allCssGlobalsToDefine, "indexHtmlCode": fs.readFileSync(pathJoin(reactAppBuildDirPath, "index.html")).toString("utf8"), @@ -139,4 +163,6 @@ export function generateKeycloakThemeResources(params: { pathJoin(themeDirPath, "theme.properties"), Buffer.from("parent=keycloak".concat("\n\n", extraThemeProperties.join("\n\n")), "utf8"), ); + + return { doBundleEmailTemplate }; } diff --git a/src/bin/create-keycloak-theme-email-directory.ts b/src/bin/create-keycloak-theme-email-directory.ts new file mode 100644 index 00000000..708daf90 --- /dev/null +++ b/src/bin/create-keycloak-theme-email-directory.ts @@ -0,0 +1,34 @@ +import { downloadBuiltinKeycloakTheme } from "./download-builtin-keycloak-theme"; +import { keycloakThemeEmailDirPath } from "./build-keycloak-theme"; +import { join as pathJoin, basename as pathBasename } from "path"; +import { transformCodebase } from "./tools/transformCodebase"; +import { promptKeycloakVersion } from "./promptKeycloakVersion"; +import * as fs from "fs"; + +if (require.main === module) { + (async () => { + if (fs.existsSync(keycloakThemeEmailDirPath)) { + console.log(`There is already a ./${pathBasename(keycloakThemeEmailDirPath)} directory in your project. Aborting.`); + + process.exit(-1); + } + + const { keycloakVersion } = await promptKeycloakVersion(); + + const builtinKeycloakThemeTmpDirPath = pathJoin(keycloakThemeEmailDirPath, "..", "xIdP3_builtin_keycloak_theme"); + + downloadBuiltinKeycloakTheme({ + keycloakVersion, + "destDirPath": builtinKeycloakThemeTmpDirPath, + }); + + transformCodebase({ + "srcDirPath": pathJoin(builtinKeycloakThemeTmpDirPath, "base", "email"), + "destDirPath": keycloakThemeEmailDirPath, + }); + + console.log(`./${pathBasename(keycloakThemeEmailDirPath)} ready to be customized`); + + fs.rmSync(builtinKeycloakThemeTmpDirPath, { "recursive": true, "force": true }); + })(); +} diff --git a/src/bin/download-builtin-keycloak-theme.ts b/src/bin/download-builtin-keycloak-theme.ts index a1721363..84a49b57 100644 --- a/src/bin/download-builtin-keycloak-theme.ts +++ b/src/bin/download-builtin-keycloak-theme.ts @@ -3,6 +3,7 @@ import { keycloakThemeBuildingDirPath } from "./build-keycloak-theme"; import { join as pathJoin } from "path"; import { downloadAndUnzip } from "./tools/downloadAndUnzip"; +import { promptKeycloakVersion } from "./promptKeycloakVersion"; export function downloadBuiltinKeycloakTheme(params: { keycloakVersion: string; destDirPath: string }) { const { keycloakVersion, destDirPath } = params; @@ -17,22 +18,16 @@ export function downloadBuiltinKeycloakTheme(params: { keycloakVersion: string; } if (require.main === module) { - const keycloakVersion = (() => { - const keycloakVersion = process.argv[2] as string | undefined; + (async () => { + const { keycloakVersion } = await promptKeycloakVersion(); - if (keycloakVersion === undefined) { - return "11.0.3"; - } + const destDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme"); - return keycloakVersion; + console.log(`Downloading builtins theme of Keycloak ${keycloakVersion} here ${destDirPath}`); + + downloadBuiltinKeycloakTheme({ + keycloakVersion, + destDirPath, + }); })(); - - const destDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme"); - - console.log(`Downloading builtins theme of Keycloak ${keycloakVersion} here ${destDirPath}`); - - downloadBuiltinKeycloakTheme({ - keycloakVersion, - destDirPath, - }); } diff --git a/src/bin/promptKeycloakVersion.ts b/src/bin/promptKeycloakVersion.ts new file mode 100644 index 00000000..59044fd6 --- /dev/null +++ b/src/bin/promptKeycloakVersion.ts @@ -0,0 +1,38 @@ +import { getLatestsSemVersionedTagFactory } from "./tools/octokit-addons/getLatestsSemVersionedTag"; +import { Octokit } from "@octokit/rest"; +import cliSelect from "cli-select"; + +export async function promptKeycloakVersion() { + const { getLatestsSemVersionedTag } = (() => { + const { octokit } = (() => { + const githubToken = process.env.GITHUB_TOKEN; + + const octokit = new Octokit(githubToken === undefined ? undefined : { "auth": githubToken }); + + return { octokit }; + })(); + + const { getLatestsSemVersionedTag } = getLatestsSemVersionedTagFactory({ octokit }); + + return { getLatestsSemVersionedTag }; + })(); + + console.log("Initialize the directory with email template from which keycloak version?"); + + const { value: keycloakVersion } = await cliSelect({ + "values": await getLatestsSemVersionedTag({ + "count": 15, + "doIgnoreBeta": true, + "owner": "keycloak", + "repo": "keycloak", + }).then(arr => arr.map(({ tag }) => tag)), + }).catch(() => { + console.log("Aborting"); + + process.exit(-1); + }); + + console.log(keycloakVersion); + + return { keycloakVersion }; +} diff --git a/src/bin/tools/NpmModuleVersion.ts b/src/bin/tools/NpmModuleVersion.ts new file mode 100644 index 00000000..aed520c7 --- /dev/null +++ b/src/bin/tools/NpmModuleVersion.ts @@ -0,0 +1,73 @@ +export type NpmModuleVersion = { + major: number; + minor: number; + patch: number; + betaPreRelease?: number; +}; + +export namespace NpmModuleVersion { + export function parse(versionStr: string): NpmModuleVersion { + const match = versionStr.match(/^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-beta.([0-9]+))?/); + + if (!match) { + throw new Error(`${versionStr} is not a valid NPM version`); + } + + return { + "major": parseInt(match[1]), + "minor": parseInt(match[2]), + "patch": parseInt(match[3]), + ...(() => { + const str = match[4]; + return str === undefined ? {} : { "betaPreRelease": parseInt(str) }; + })(), + }; + } + + export function stringify(v: NpmModuleVersion) { + return `${v.major}.${v.minor}.${v.patch}${v.betaPreRelease === undefined ? "" : `-beta.${v.betaPreRelease}`}`; + } + + /** + * + * v1 < v2 => -1 + * v1 === v2 => 0 + * v1 > v2 => 1 + * + */ + export function compare(v1: NpmModuleVersion, v2: NpmModuleVersion): -1 | 0 | 1 { + const sign = (diff: number): -1 | 0 | 1 => (diff === 0 ? 0 : diff < 0 ? -1 : 1); + const noUndefined = (n: number | undefined) => n ?? Infinity; + + for (const level of ["major", "minor", "patch", "betaPreRelease"] as const) { + if (noUndefined(v1[level]) !== noUndefined(v2[level])) { + return sign(noUndefined(v1[level]) - noUndefined(v2[level])); + } + } + + return 0; + } + + /* + console.log(compare(parse("3.0.0-beta.3"), parse("3.0.0")) === -1 ) + console.log(compare(parse("3.0.0-beta.3"), parse("3.0.0-beta.4")) === -1 ) + console.log(compare(parse("3.0.0-beta.3"), parse("4.0.0")) === -1 ) + */ + + export function bumpType(params: { versionBehindStr: string; versionAheadStr: string }): "major" | "minor" | "patch" | "betaPreRelease" | "same" { + const versionAhead = parse(params.versionAheadStr); + const versionBehind = parse(params.versionBehindStr); + + if (compare(versionBehind, versionAhead) === 1) { + throw new Error(`Version regression ${versionBehind} -> ${versionAhead}`); + } + + for (const level of ["major", "minor", "patch", "betaPreRelease"] as const) { + if (versionBehind[level] !== versionAhead[level]) { + return level; + } + } + + return "same"; + } +} diff --git a/src/bin/tools/createOctokit.ts b/src/bin/tools/createOctokit.ts new file mode 100644 index 00000000..a3eb5395 --- /dev/null +++ b/src/bin/tools/createOctokit.ts @@ -0,0 +1,7 @@ +import { Octokit } from "@octokit/rest"; + +export function createOctokit(params: { github_token: string }) { + const { github_token } = params; + + return new Octokit({ ...(github_token !== "" ? { "auth": github_token } : {}) }); +} diff --git a/src/bin/tools/octokit-addons/getLatestsSemVersionedTag.ts b/src/bin/tools/octokit-addons/getLatestsSemVersionedTag.ts new file mode 100644 index 00000000..f3fb505b --- /dev/null +++ b/src/bin/tools/octokit-addons/getLatestsSemVersionedTag.ts @@ -0,0 +1,40 @@ +import { listTagsFactory } from "./listTags"; +import type { Octokit } from "@octokit/rest"; +import { NpmModuleVersion } from "../NpmModuleVersion"; + +export function getLatestsSemVersionedTagFactory(params: { octokit: Octokit }) { + const { octokit } = params; + + async function getLatestsSemVersionedTag(params: { owner: string; repo: string; doIgnoreBeta: boolean; count: number }): Promise< + { + tag: string; + version: NpmModuleVersion; + }[] + > { + const { owner, repo, doIgnoreBeta, count } = params; + + const semVersionedTags: { tag: string; version: NpmModuleVersion }[] = []; + + const { listTags } = listTagsFactory({ octokit }); + + for await (const tag of listTags({ owner, repo })) { + let version: NpmModuleVersion; + + try { + version = NpmModuleVersion.parse(tag.replace(/^[vV]?/, "")); + } catch { + continue; + } + + if (doIgnoreBeta && version.betaPreRelease !== undefined) { + continue; + } + + semVersionedTags.push({ tag, version }); + } + + return semVersionedTags.sort(({ version: vX }, { version: vY }) => NpmModuleVersion.compare(vY, vX)).slice(0, count); + } + + return { getLatestsSemVersionedTag }; +} diff --git a/src/bin/tools/octokit-addons/listTags.ts b/src/bin/tools/octokit-addons/listTags.ts new file mode 100644 index 00000000..48881659 --- /dev/null +++ b/src/bin/tools/octokit-addons/listTags.ts @@ -0,0 +1,49 @@ +import type { Octokit } from "@octokit/rest"; + +const per_page = 99; + +export function listTagsFactory(params: { octokit: Octokit }) { + const { octokit } = params; + + const octokit_repo_listTags = async (params: { owner: string; repo: string; per_page: number; page: number }) => { + return octokit.repos.listTags(params); + }; + + async function* listTags(params: { owner: string; repo: string }): AsyncGenerator { + const { owner, repo } = params; + + let page = 1; + + while (true) { + const resp = await octokit_repo_listTags({ + owner, + repo, + per_page, + "page": page++, + }); + + for (const branch of resp.data.map(({ name }) => name)) { + yield branch; + } + + if (resp.data.length < 99) { + break; + } + } + } + + /** Returns the same "latest" tag as deno.land/x, not actually the latest though */ + async function getLatestTag(params: { owner: string; repo: string }): Promise { + const { owner, repo } = params; + + const itRes = await listTags({ owner, repo }).next(); + + if (itRes.done) { + return undefined; + } + + return itRes.value; + } + + return { listTags, getLatestTag }; +} diff --git a/src/test/bin/generateKeycloakThemeResources.ts b/src/test/bin/generateKeycloakThemeResources.ts index c314b61e..e30a7a49 100644 --- a/src/test/bin/generateKeycloakThemeResources.ts +++ b/src/test/bin/generateKeycloakThemeResources.ts @@ -8,6 +8,7 @@ generateKeycloakThemeResources({ "themeName": "keycloakify-demo-app", "reactAppBuildDirPath": pathJoin(sampleReactProjectDirPath, "build"), "keycloakThemeBuildingDirPath": pathJoin(sampleReactProjectDirPath, "build_keycloak_theme"), + "keycloakThemeEmailDirPath": pathJoin(sampleReactProjectDirPath, "keycloak_theme_email"), "urlPathname": "/keycloakify-demo-app/", "urlOrigin": undefined, "extraPagesId": ["my-custom-page.ftl"], diff --git a/yarn.lock b/yarn.lock index 4ae7c387..3dcbeba8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -111,6 +111,107 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== +"@octokit/auth-token@^2.4.4": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36" + integrity sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g== + dependencies: + "@octokit/types" "^6.0.3" + +"@octokit/core@^3.5.1": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.6.0.tgz#3376cb9f3008d9b3d110370d90e0a1fcd5fe6085" + integrity sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q== + dependencies: + "@octokit/auth-token" "^2.4.4" + "@octokit/graphql" "^4.5.8" + "@octokit/request" "^5.6.3" + "@octokit/request-error" "^2.0.5" + "@octokit/types" "^6.0.3" + before-after-hook "^2.2.0" + universal-user-agent "^6.0.0" + +"@octokit/endpoint@^6.0.1": + version "6.0.12" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658" + integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA== + dependencies: + "@octokit/types" "^6.0.3" + is-plain-object "^5.0.0" + universal-user-agent "^6.0.0" + +"@octokit/graphql@^4.5.8": + version "4.8.0" + resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3" + integrity sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg== + dependencies: + "@octokit/request" "^5.6.0" + "@octokit/types" "^6.0.3" + universal-user-agent "^6.0.0" + +"@octokit/openapi-types@^11.2.0": + version "11.2.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-11.2.0.tgz#b38d7fc3736d52a1e96b230c1ccd4a58a2f400a6" + integrity sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA== + +"@octokit/plugin-paginate-rest@^2.16.8": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz#32e9c7cab2a374421d3d0de239102287d791bce7" + integrity sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw== + dependencies: + "@octokit/types" "^6.34.0" + +"@octokit/plugin-request-log@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85" + integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA== + +"@octokit/plugin-rest-endpoint-methods@^5.12.0": + version "5.13.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz#8c46109021a3412233f6f50d28786f8e552427ba" + integrity sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA== + dependencies: + "@octokit/types" "^6.34.0" + deprecation "^2.3.1" + +"@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677" + integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg== + dependencies: + "@octokit/types" "^6.0.3" + deprecation "^2.0.0" + once "^1.4.0" + +"@octokit/request@^5.6.0", "@octokit/request@^5.6.3": + version "5.6.3" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.3.tgz#19a022515a5bba965ac06c9d1334514eb50c48b0" + integrity sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A== + dependencies: + "@octokit/endpoint" "^6.0.1" + "@octokit/request-error" "^2.1.0" + "@octokit/types" "^6.16.1" + is-plain-object "^5.0.0" + node-fetch "^2.6.7" + universal-user-agent "^6.0.0" + +"@octokit/rest@^18.12.0": + version "18.12.0" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.12.0.tgz#f06bc4952fc87130308d810ca9d00e79f6988881" + integrity sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q== + dependencies: + "@octokit/core" "^3.5.1" + "@octokit/plugin-paginate-rest" "^2.16.8" + "@octokit/plugin-request-log" "^1.0.4" + "@octokit/plugin-rest-endpoint-methods" "^5.12.0" + +"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.34.0": + version "6.34.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.34.0.tgz#c6021333334d1ecfb5d370a8798162ddf1ae8218" + integrity sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw== + dependencies: + "@octokit/openapi-types" "^11.2.0" + "@types/mdast@^3.0.0", "@types/mdast@^3.0.3": version "3.0.10" resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" @@ -118,10 +219,10 @@ dependencies: "@types/unist" "*" -"@types/node@^10.0.0": - version "10.17.60" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" - integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== +"@types/node@^17.0.25": + version "17.0.25" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.25.tgz#527051f3c2f77aa52e5dc74e45a3da5fb2301448" + integrity sha512-wANk6fBrUwdpY4isjWrKTufkrXdu1D2YHCot2fD/DfWxF5sMrVSA+KN7ydckvaTCh0HiqX9IVl0L5/ZoXg5M7w== "@types/parse-json@^4.0.0": version "4.0.0" @@ -165,6 +266,11 @@ ansi-colors@^4.1.1: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== +ansi-escapes@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + ansi-escapes@^4.3.0: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -206,6 +312,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +before-after-hook@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" + integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ== + boolbase@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -304,6 +415,13 @@ cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" +cli-select@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/cli-select/-/cli-select-1.1.2.tgz#456dced464b3346ca661b16a0e37fc4b28db4818" + integrity sha512-PSvWb8G0PPmBNDcz/uM2LkZN3Nn5JmhUl465tTfynQAXjKzFpmHbxStM6X/+awKp5DJuAaHMzzMPefT0suGm1w== + dependencies: + ansi-escapes "^3.2.0" + cli-truncate@2.1.0, cli-truncate@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" @@ -439,6 +557,11 @@ debug@^4.0.0, debug@^4.3.2: dependencies: ms "2.1.2" +deprecation@^2.0.0, deprecation@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" + integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== + dom-serializer@^1.0.1, dom-serializer@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" @@ -789,6 +912,11 @@ is-plain-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== + is-promise@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" @@ -998,6 +1126,13 @@ next-tick@~1.0.0: resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= +node-fetch@^2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + noms@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859" @@ -1030,7 +1165,7 @@ object-assign@^4.1.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= -once@^1.3.0: +once@^1.3.0, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= @@ -1475,6 +1610,11 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + trough@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" @@ -1580,6 +1720,11 @@ unist-util-visit@^2.0.0: unist-util-is "^4.0.0" unist-util-visit-parents "^3.0.0" +universal-user-agent@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" + integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== + untildify@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" @@ -1608,6 +1753,19 @@ vfile@^4.0.0: unist-util-stringify-position "^2.0.0" vfile-message "^2.0.0" +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which-pm-runs@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb"