diff --git a/README.md b/README.md index 56604df..5265de9 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,16 @@ ```sh npx supported npx supported <[array/of/node_modules]> +// Generate token using https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token +npx supported https://github.com/stefanpenner/supported +npx supported https://github.com/stefanpenner/supported/tree/some-branch +npx supported https://test.githubprivate.com/stefanpenner/supported -t $TOKEN +npx supported supported --hostUrl=https://raw.githubusercontent.com/stefanpenner/supported/main/ ``` -#### Optional Flags +### Optional Flags +#### current date The `--current-date` (`-c`) flag enables a form of limited time travel, and attempts to run the tools internal date calculations based on a specified date, rather then the current date. @@ -26,6 +32,21 @@ Anything that `new Date(input)` parses, or if that fails it will assume to be a relative duration starting today parsed by [parse-duration@^1.0.0's own micro-syntax](https://github.com/jkroso/parse-duration#available-unit-types-are). +#### hostURL +The `--hostURL` flag enables a way to provide a valid URL which will return package.json, lock file and npmrc file if exists. +some examples: + +* `--hostUrl=https://raw.githubusercontent.com/stefanpenner/supported/main/`, gets the above listed file from the provided URL. +* `--hostUrl=https://${TOKEN}@raw.githubprivate.com/stefanpenner/supported/main/`, gets the above listed file from the private instance URL provided, +private instance needs token, that must be passed as part of URL. + +#### token +The `--token` (`-t`) is to pass the token generated to access the private instances of the github. This will enable this tool to evaluate +the github private instance repositories. Generating a personal access token is explained in detail [here](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token). + +Example: +`supported https://test.githubprivate.com/stefanpenner/supported -t $TOKEN` + ### As a node module diff --git a/lib/cli.js b/lib/cli.js index e49c006..fce6cc7 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -9,6 +9,7 @@ const { displayResults } = require('../lib/output/cli-output'); const { processPolicies } = require('../lib/project/multiple-projects'); const { DEFAULT_SUPPORT_MESSAGE } = require('./output/messages'); const { generateCsv } = require('../lib/output/csv-output'); +const { inputHasGithubPrivate } = require('./util'); async function main(cli, { policyDetails, setupProjectFn }) { const projectPaths = handleInput(cli.input, process.cwd()); @@ -22,7 +23,7 @@ async function main(cli, { policyDetails, setupProjectFn }) { let result; let processed = false; try { - result = await processPolicies(projectPaths, setupProjectFn, spinner, currentDate); + result = await processPolicies(projectPaths, setupProjectFn, spinner, currentDate, cli.flags); if (result.isInSupportWindow === false) { process.exitCode = 1; } @@ -87,6 +88,14 @@ async function run( type: 'string', alias: 'c', }, + token: { + type: 'string', + alias: 't', + isRequired: inputHasGithubPrivate, + }, + hostUrl: { + type: 'string', + }, }, }), { policyDetails, setupProjectFn }, diff --git a/lib/help.js b/lib/help.js index 2f96676..1a6e04b 100644 --- a/lib/help.js +++ b/lib/help.js @@ -18,7 +18,12 @@ module.exports = (commandName = 'supported', packageLink = pkg.homepage) => { {cyan --supported, -s} outputs detailed report of supported packages only {cyan --csv} outputs csv file in the project path {cyan --current-date, -c} optional current date to use when calculating support + {cyan --token, -t} token to access raw file from github private instance + {cyan --hostUrl} URL endpoint that returns package.json, yarn.lock and npmrc files. {bold Examples} {gray $} {cyan ${commandName} ./path/to/project/} + {gray $} {cyan ${commandName} https://github.com/stefanpenner/supported} + {gray $} {cyan ${commandName} https://test.githubprivate.com/stefanpenner/supported -t $TOKEN} + {gray $} {cyan ${commandName} supported --hostUrl=https://raw.githubusercontent.com/stefanpenner/supported/main/} `; }; diff --git a/lib/lts/ember-lts.json b/lib/lts/ember-lts.json index ad8e041..84824ee 100644 --- a/lib/lts/ember-lts.json +++ b/lib/lts/ember-lts.json @@ -1,14 +1,14 @@ { - "3.16.*": { - "versionRange": "3.16.*", - "start_date": "2020-03-04T00:00:00.000Z", - "maintenance_start_date": "2020-11-11T00:00:00.000Z", - "end_date": "2021-03-17T00:00:00.000Z" - }, "3.20.*": { "versionRange": ">=3.20.*", "start_date": "2020-08-24T00:00:00.000Z", "maintenance_start_date": "2021-05-03T00:00:00.000Z", "end_date": "2021-09-06T00:00:00.000Z" + }, + "3.24.*": { + "versionRange": ">=3.24.*", + "start_date": "2021-02-25T00:00:00.000Z", + "maintenance_start_date": "2021-11-04T00:00:00.000Z", + "end_date": "2022-03-10T00:00:00.000Z" } } \ No newline at end of file diff --git a/lib/project/multiple-projects.js b/lib/project/multiple-projects.js index adb00e9..433fd5a 100644 --- a/lib/project/multiple-projects.js +++ b/lib/project/multiple-projects.js @@ -10,7 +10,7 @@ const { ProgressLogger } = require('../util'); const DEFAULT_SETUP_FILE = './setup-project'; module.exports.processPolicies = processPolicies; -async function processPolicies(projectPaths, setupProjectFn, spinner, today) { +async function processPolicies(projectPaths, setupProjectFn, spinner, today, flags) { const setupProject = setupProjectFn ? setupProjectFn : require(DEFAULT_SETUP_FILE); let result = { isInSupportWindow: true, @@ -29,7 +29,7 @@ async function processPolicies(projectPaths, setupProjectFn, spinner, today) { for (const projectPath of projectPaths) { work.push( queue.add(async () => { - let { dependenciesToCheck, pkg } = await setupProject(projectPath); + let { dependenciesToCheck, pkg } = await setupProject(projectPath, flags); progressLogger.updateTotalDepCount(dependenciesToCheck.length); let auditResult = await isInSupportWindow( dependenciesToCheck, diff --git a/lib/project/setup-project.js b/lib/project/setup-project.js index 00251d5..6fcef3a 100644 --- a/lib/project/setup-project.js +++ b/lib/project/setup-project.js @@ -3,32 +3,65 @@ const semverCoerce = require('semver/functions/coerce'); const YarnLockfile = require('@yarnpkg/lockfile'); const npa = require('npm-package-arg'); +const ini = require('ini'); const fs = require('fs'); const path = require('path'); const debug = require('debug')('supported:project'); +const { setupProjectPath } = require('../read-from-url'); const npmConfig = require('../npm/config'); -module.exports = async function setupProject(projectRoot) { - const config = await npmConfig(projectRoot); // kinda slow, TODO: re-implement as standalone lib - // const { policies } = options; - const pkgPath = `${projectRoot}/package.json`; - if (!fs.existsSync(pkgPath)) { - throw new Error(`${pkgPath} does not exist, are you sure this is a valid package?`); - } - if (!fs.statSync(pkgPath).isFile()) { - throw new Error(`${pkgPath} is not a file, are you sure this is a valid package?`); +module.exports = async function setupProject(projectRoot, flags = {}) { + let projectInfo = {}; + if (!fs.existsSync(projectRoot)) { + projectInfo = await setupProjectPath(projectRoot, { + token: flags.token, + hostUrl: flags.hostUrl, + }); + // if project root is a URL then use homedir as root + projectRoot = require('os').homedir(); } - const file = fs.readFileSync(pkgPath, 'utf-8'); - let pkg; - try { - pkg = JSON.parse(file); - } catch (e) { - throw new Error(`${pkgPath} is not a valid JSON file, are you sure this is a valid package?`); + + let config = await npmConfig(projectRoot); // kinda slow, TODO: re-implement as standalone lib + let pkg = {}; + let lockfileContent = ''; + if (projectInfo.packageJSON) { + pkg = projectInfo.packageJSON; + lockfileContent = projectInfo['yarn.lock']; + if (projectInfo['.npmrc']) { + try { + let localConfig = ini.parse(projectInfo['.npmrc']); + config = { + config, + ...localConfig, + }; + } catch (e) { + throw new Error( + `Couldn't parse the npmrc file, are you sure project URL has a valid npmrc?\n ${e}`, + ); + } + } + } else { + const pkgPath = `${projectRoot}/package.json`; + if (!fs.existsSync(pkgPath)) { + throw new Error(`${pkgPath} does not exist, are you sure this is a valid package?`); + } + if (!fs.statSync(pkgPath).isFile()) { + throw new Error(`${pkgPath} is not a file, are you sure this is a valid package?`); + } + const file = fs.readFileSync(pkgPath, 'utf-8'); + try { + pkg = JSON.parse(file); + } catch (e) { + throw new Error(`${pkgPath} is not a valid JSON file, are you sure this is a valid package?`); + } + const lockfilePath = path.join(projectRoot, 'yarn.lock'); + lockfileContent = fs.readFileSync(lockfilePath, 'utf-8'); } + // const { policies } = options; const lockfilePath = path.join(projectRoot, 'yarn.lock'); // TODO: npm support - const { object: lockfile } = YarnLockfile.parse(fs.readFileSync(lockfilePath, 'utf-8')); + const { object: lockfile } = YarnLockfile.parse(lockfileContent); const dependenciesToCheck = []; if (pkg.dependencies) { diff --git a/lib/read-from-url.js b/lib/read-from-url.js new file mode 100644 index 0000000..aa880af --- /dev/null +++ b/lib/read-from-url.js @@ -0,0 +1,85 @@ +'use strict'; +const fetch = require('minipass-fetch'); +const debug = require('debug')('supported:read-from-url'); +const { default: PQueue } = require('p-queue'); +const allSettled = require('promise.allsettled'); +const os = require('os'); +const { getFetchUrl } = require('./util'); +const chalk = require('chalk'); + +async function setupProjectPath(_url, options = {}) { + let url = getFetchUrl(_url, options); + + const work = []; + const queue = new PQueue({ + concurrency: os.cpus().length, + }); + let result = Object.create(null); + let packageJSON; + // check if the code moved to main or still using master + // https://github.com/SparshithNR/doc-tester/blob/master/package.json + // https://github.com/stefanpenner/supported/blob/main/package.json + try { + packageJSON = await runFetch(url + 'package.json', true); + } catch (e) { + if (e.code === 404) { + url = url.replace('main', 'master'); + packageJSON = await runFetch(url + 'package.json', true); + } else { + throw e; + } + } + for (const fileName of ['yarn.lock', '.npmrc']) { + work.push( + queue.add(async () => { + const requestURL = url + fileName; + result[fileName] = await runFetch(requestURL); + }), + ); + } + await queue.onIdle(); + for (const settled of await allSettled(work)) { + if (settled.status === 'rejected') { + throw settled.reason; + } + } + + debug(`packageJSON url: ${url.toString()}`); + + return { + packageJSON, + ...result, + }; +} + +async function runFetch(requestURL, isJson) { + let response; + try { + response = await fetch(requestURL); + } catch (e) { + let error = new Error(chalk`{red Couldn't reach server, please check the URL provided.} + ${e.message}`); + throw error; + } + if (response.status === 200) { + if (isJson) { + return response.json(); + } + return response.text(); + } else if (response.status === 404) { + if (!requestURL.includes('.npmrc')) { + const text = await response.buffer(); + const e = new Error(`[http.status=${response.status}] url:${requestURL} : error: ${text}`); + e.code = response.status; + throw e; + } else { + debug(`Fetch failed for .npmrc , ${await response.buffer()}`); + } + } else { + throw new Error(`[http.status=${response.status}] url:${requestURL}`); + } +} + +module.exports = { + setupProjectPath, +}; diff --git a/lib/util.js b/lib/util.js index 460292d..dd4f85d 100644 --- a/lib/util.js +++ b/lib/util.js @@ -14,6 +14,12 @@ exports.MS_IN_QTR = MS_IN_QTR; // expiring soon if the package expires within 4 qtrs const THRESHOLD_QTRS = 5; +// github url constants +const RAW_CONTENT_HOST = 'raw.githubusercontent.com'; +const GITHUB_PRIVATE = 'githubprivate'; +const GITHUB = 'github.com'; +const MISSING_TOKEN = chalk`{red Private instances of github needs token. To generate token follow https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token}`; + /** * * @param {int} timeDiff duration between latest version and resolved version release date @@ -232,3 +238,55 @@ module.exports.handleInput = function (input, cwd) { return input; } }; + +/** + * Generates the fetch URL to get package.json and other required files. + */ +module.exports.getFetchUrl = function (_url, options = {}) { + let { token, hostUrl } = options; + _url = hostUrl || _url; + _url += _url.endsWith('/') ? '' : '/'; + if (hostUrl) { + return _url; + } + let url = new URL(_url); + let branch = url.pathname.indexOf('/tree/'); + let hostname = url.hostname; + let pathname = url.pathname; + if (hostname.includes(GITHUB)) { + hostname = RAW_CONTENT_HOST; + if (branch == -1) { + pathname += 'main/'; + } + } else if (hostname.includes(GITHUB_PRIVATE)) { + if (!token) { + throw new Error(MISSING_TOKEN); + } + hostname = `${token}@raw.${hostname}`; + if (branch == -1) { + pathname += 'master/'; + } + } + if (branch !== -1) { + pathname = pathname.replace('/tree/', '/'); + } + let currentURL = url.toString(); + currentURL = currentURL.replace(url.hostname, hostname); + currentURL = currentURL.replace(url.pathname, pathname); + currentURL += currentURL.endsWith('/') ? '' : '/'; + return currentURL; +}; + +/** + * Returns true if the given list of input has private instance, and token is provided. + */ +module.exports.inputHasGithubPrivate = function (flags, input) { + input = Array.isArray(input) ? input : [input]; + let isPrivate = input.some(inputUrl => { + return inputUrl.includes(GITHUB_PRIVATE); + }); + if (isPrivate && !flags.token) { + console.log(MISSING_TOKEN); + } + return isPrivate; +}; diff --git a/package.json b/package.json index 0b0dca6..af66a21 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "cli-table": "^0.3.4", "debug": "^4.3.1", "execa": "^5.0.0", - "ini": "^1.3.7", + "ini": "^2.0.0", "json2csv": "^5.0.6", "koa": "^2.13.0", "meow": "^8.0.0", diff --git a/tests/cli-test.js b/tests/cli-test.js index ef35441..754c995 100644 --- a/tests/cli-test.js +++ b/tests/cli-test.js @@ -36,8 +36,15 @@ describe('CLI', function () { // Test in windows are failing // Issue may be caused by npmconfig command we have in the code base. For now we are increasing the timeout. this.timeout(4000); + let FILE_SERVER_PORT_1 = 3005; beforeEach(function () { - registries.startAll(); + registries.startAll([ + { + name: 'supported-project', + recordingRoot: `./tests/fixtures/supported-project`, + port: FILE_SERVER_PORT_1, + }, + ]); }); afterEach(function () { @@ -133,6 +140,38 @@ describe('CLI', function () { expect(child.stdout).to.includes('✗ unsupported-project'); expect(child.stdout).to.includes('✓ supported-project'); }); + + it('works against a fully supported project with hosturl', async function () { + const child = await runSupportedCmd([ + `supported-project`, + '--hostUrl', + `http://localhost:${FILE_SERVER_PORT_1}/`, + ]); + expect(child.exitCode).to.eql(0); + expect(child.stderr).to.includes('✓ SemVer Policy'); + expect(child.stdout).to.includes('Congrats!'); + }); + + it('error out when token not passed for github private instance', async function () { + const child = await runSupportedCmd([ + `https://test.githubprivate.com/stefanpenner/supported`, + ]); + expect(child.exitCode).to.eql(2); + expect(child.stderr).to.includes('Missing required flag\n\t--token, -t'); + expect(child.stdout).to.includes( + `Private instances of github needs token. To generate token follow https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token`, + ); + }); + + it('error out with clear message when url is not reachable', async function () { + const child = await runSupportedCmd([ + `https://test.githubprivate.com/stefanpenner/supported`, + '-t', + 'abac', + ]); + expect(child.exitCode).to.eql(1); + expect(child.stderr).to.includes(`Couldn't reach server, please check the URL provided`); + }); }); describe('--verbose', function () { diff --git a/tests/read-from-url-test.js b/tests/read-from-url-test.js new file mode 100644 index 0000000..74e3237 --- /dev/null +++ b/tests/read-from-url-test.js @@ -0,0 +1,51 @@ +'use strict'; + +const { expect } = require('chai'); +const { setupProjectPath } = require('../lib/read-from-url'); +const fileServer = require('./test-helpers/registries'); + +describe('read file from URL', function () { + const FILE_SERVER_PORT_1 = 3454; + const FILE_SERVER_PORT_2 = 3455; + beforeEach(function () { + let root = `./tests/fixtures`; + fileServer.startAll([ + { + name: 'supported-project', + recordingRoot: `${root}/supported-project`, + port: FILE_SERVER_PORT_1, + }, + { + name: 'not-found-project', + recordingRoot: `${root}/not-found-project`, + port: FILE_SERVER_PORT_2, + }, + ]); + }); + + afterEach(function () { + fileServer.stopAll(); + }); + + it('package.json and yarn.lock and .npmrc is created', async function () { + let projectInfo = await setupProjectPath( + `http://github.com:${FILE_SERVER_PORT_1}/supported-project`, + { + hostUrl: `http://localhost:${FILE_SERVER_PORT_1}`, + }, + ); + expect(projectInfo.packageJSON.name).to.equal('supported-project'); + expect(projectInfo['yarn.lock']).to.include('# yarn lockfile v1'); + expect(projectInfo['.npmrc']).to.include('@stefanpenner:registry=http://0.0.0.0:3001'); + }); + + it('throws file not found error', async function () { + try { + await setupProjectPath(`http://github.com:${FILE_SERVER_PORT_2}/supported-projects`, { + hostUrl: `http://localhost:${FILE_SERVER_PORT_2}`, + }); + } catch (e) { + expect(e.code).to.eq(404); + } + }); +}); diff --git a/tests/test-helpers/registries.js b/tests/test-helpers/registries.js index 9556fb5..5e0d8f9 100644 --- a/tests/test-helpers/registries.js +++ b/tests/test-helpers/registries.js @@ -3,6 +3,7 @@ const Koa = require('koa'); const fs = require('fs'); const resolve = require('resolve-path'); +const { extname } = require('path'); const BASE_PORT = 3000; // disable inherited registry (when calling yarn you get this set...) @@ -13,9 +14,16 @@ function server(recordingRoot, port) { app.use(async (ctx, next) => { if (ctx.method === 'GET') { - const moduleName = ctx.url.slice(1); - // use resolve-path to prevent directory traversal - const file = resolve(recordingRoot, `${moduleName}.json`); + let urlSplit = ctx.url.split('/'); + let file = urlSplit[urlSplit.length - 1]; + // check if the request is for a specific file. + if (extname(file) || file === '.npmrc') { + file = resolve(recordingRoot, file); + } else { + const moduleName = ctx.url.slice(1); + // use resolve-path to prevent directory traversal + file = resolve(recordingRoot, `${moduleName}.json`); + } if (fs.existsSync(file)) { ctx.body = fs.readFileSync(file, 'UTF8'); } else { @@ -52,8 +60,9 @@ function server(recordingRoot, port) { // registry for the @stefanpenner scope registries.stefanpenner = server(`${root}/recordings/stefanpenner`, BASE_PORT + 1); // if developers want to add more server while extending - additionalRegistries.forEach(({ name, recordingRoot }, index) => { - registries[name] = server(recordingRoot, BASE_PORT + 2 + index); + additionalRegistries.forEach(({ name, recordingRoot, port }, index) => { + port = port || BASE_PORT + 2 + index; + registries[name] = server(recordingRoot, port); }); }; diff --git a/tests/util-test.js b/tests/util-test.js index 60558e9..323db75 100644 --- a/tests/util-test.js +++ b/tests/util-test.js @@ -2,7 +2,13 @@ const chai = require('chai'); const { expect } = chai; -const { sortLibraries, checkNodeCompatibility, handleInput } = require('../lib/util'); +const { + sortLibraries, + checkNodeCompatibility, + handleInput, + getFetchUrl, + inputHasGithubPrivate, +} = require('../lib/util'); chai.use(require('chai-datetime')); @@ -172,4 +178,66 @@ describe('util test', function () { ]); }); }); + describe('getFetchUrl', function () { + it('returns hosturl', function () { + expect(getFetchUrl('test-url.com', { hostUrl: 'localhost:3400' })).to.be.eql( + 'localhost:3400/', + ); + }); + it('returns github content url', function () { + expect(getFetchUrl('https://github.com/stefanpenner/supported')).to.be.eql( + 'https://raw.githubusercontent.com/stefanpenner/supported/main/', + ); + }); + it('returns github content url with given branch', function () { + expect( + getFetchUrl('https://github.com/stefanpenner/supported/tree/error-out-node'), + ).to.be.eql('https://raw.githubusercontent.com/stefanpenner/supported/error-out-node/'); + }); + it('returns github content url private repo', function () { + expect( + getFetchUrl('https://test.githubprivate.com/stefanpenner/supported/', { token: 'a1b2c3' }), + ).to.be.eql('https://a1b2c3@raw.test.githubprivate.com/stefanpenner/supported/master/'); + }); + it('returns github content url private repo with given branch', function () { + expect( + getFetchUrl('https://test.githubprivate.com/stefanpenner/supported/tree/error-out-node', { + token: 'a1b2c3', + }), + ).to.be.eql( + 'https://a1b2c3@raw.test.githubprivate.com/stefanpenner/supported/error-out-node/', + ); + }); + it('errors github content url private repo with no token', function () { + expect(() => { + getFetchUrl('https://test.githubprivate.com/stefanpenner/supported/tree/error-out-node'); + }).throws( + /Private instances of github needs token. To generate token follow https:\/\/docs.github.com\/en\/github\/authenticating-to-github\/creating-a-personal-access-token/, + ); + }); + }); + + describe('inputHasGithubPrivate', function () { + //setting token to true so that console.log won't appear. + it('return true if github private instance present', function () { + expect( + inputHasGithubPrivate( + { token: true }, + 'https://test.githubprivate.com/stefanpenner/supported/', + ), + ).to.be.true; + }); + it('return false if github private instance present', function () { + expect(inputHasGithubPrivate({ token: true }, 'https://test.com/stefanpenner/supported/')).to + .be.false; + }); + it('return true if github private instance present in multiple inputs', function () { + expect( + inputHasGithubPrivate({ token: true }, [ + 'https://test.com/stefanpenner/supported/', + 'https://test.githubprivate.com/stefanpenner/supported/', + ]), + ).to.be.true; + }); + }); }); diff --git a/yarn.lock b/yarn.lock index b776274..31ecf0b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -678,7 +678,7 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: +es-abstract@^1.18.0-next.1: version "1.18.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0.tgz#ab80b359eecb7ede4c298000390bc5ac3ec7b5a4" integrity sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw== @@ -700,6 +700,26 @@ es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.0" +es-abstract@^1.18.0-next.2: + version "1.18.0-next.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.2.tgz#088101a55f0541f595e7e057199e27ddc8f3a5c2" + integrity sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.2.2" + is-negative-zero "^2.0.1" + is-regex "^1.1.1" + object-inspect "^1.9.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.3" + string.prototype.trimstart "^1.0.3" + es-array-method-boxes-properly@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" @@ -1039,7 +1059,16 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.0.tgz#892e62931e6938c8a23ea5aaebcfb67bd97da97e" + integrity sha512-M11rgtQp5GZMZzDL7jLTNxbDfurpzuau5uqRWDPvlHjfvg3TdScAZo96GLvhMjImrmR8uAt0FS2RLoMrfWGKlg== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-intrinsic@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== @@ -1280,10 +1309,10 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.7: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== +ini@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" + integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== ip@^1.1.5: version "1.1.5" @@ -1321,7 +1350,7 @@ is-boolean-object@^1.1.0: dependencies: call-bind "^1.0.0" -is-callable@^1.1.4, is-callable@^1.2.3: +is-callable@^1.1.4, is-callable@^1.2.2, is-callable@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== @@ -1405,7 +1434,7 @@ is-plain-obj@^2.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== -is-regex@^1.1.2: +is-regex@^1.1.1, is-regex@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.2.tgz#81c8ebde4db142f2cf1c53fc86d6a45788266251" integrity sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg== @@ -2537,6 +2566,14 @@ string.prototype.padend@^3.0.0: define-properties "^1.1.3" es-abstract "^1.18.0-next.2" +string.prototype.trimend@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz#a22bd53cca5c7cf44d7c9d5c732118873d6cd18b" + integrity sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + string.prototype.trimend@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" @@ -2545,6 +2582,14 @@ string.prototype.trimend@^1.0.4: call-bind "^1.0.2" define-properties "^1.1.3" +string.prototype.trimstart@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz#9b4cb590e123bb36564401d59824298de50fd5aa" + integrity sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + string.prototype.trimstart@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed"