diff --git a/__tests__/require-memo.ts b/__tests__/require-memo.ts index c360228..eaa5e24 100644 --- a/__tests__/require-memo.ts +++ b/__tests__/require-memo.ts @@ -1,5 +1,6 @@ import { RuleTester } from "eslint"; import rule from "../require-memo"; +import { normalizeIndent } from '../utils'; const ruleTester = new RuleTester({ parser: require.resolve("@typescript-eslint/parser"), @@ -11,72 +12,130 @@ const ruleTester = new RuleTester({ ruleTester.run("memo", rule, { valid: [ { - code: `const Component = React.memo(() =>
)`, + code: normalizeIndent` + const Component = memo(() =>
) + `, }, { - code: `const Component = memo(() =>
)`, + code: normalizeIndent` + const Component = memo(() =>
) + `, }, { - code: `const Component = memo(useRef(() =>
))`, + code: normalizeIndent` + const Component = memo(useRef(() =>
)) + `, }, { - code: `const Component = React.useRef(React.memo(() =>
))`, + code: normalizeIndent` + const Component = useRef(memo(() =>
)) + `, }, { - code: `const myFunction = () =>
`, + code: normalizeIndent` + const myFunction = () =>
+ `, }, { - code: `const myFunction = wrapper(() =>
)`, + code: normalizeIndent` + const myFunction = wrapper(() =>
) + `, }, { - code: `const Component = React.memo(function() { return
; });`, + code: normalizeIndent` + const Component = memo(function() { return
; }); + `, }, { - code: `const Component = memo(function Component() { return
; });`, + code: normalizeIndent` + const Component = memo(function Component() { return
; }); + `, }, { - code: `const myFunction = () =>
`, + code: normalizeIndent` + const myFunction = () =>
+ `, }, { - code: `const myFunction = wrapper(() =>
)`, + code: normalizeIndent` + const myFunction = wrapper(() =>
) + `, }, { - code: `function myFunction() { return
; }`, + code: normalizeIndent` + function myFunction() { return
; } + `, }, { - code: `const myFunction = wrapper(function() { return
})`, + code: normalizeIndent` + const myFunction = wrapper(function() { return
}) + `, }, { filename: "dir/myFunction.js", parserOptions: { ecmaVersion: 6, sourceType: "module" }, - code: `export default function() { return
};`, + code: normalizeIndent` + export default function() { return
}; + `, }, ], invalid: [ { - code: `const Component = () =>
`, + code: `import { memo } from 'react' +const Component = () =>
`, errors: [{ messageId: "memo-required" }], + output: `import { memo } from 'react' +const Component = memo(() =>
)` }, { - code: `const Component = useRef(() =>
)`, + code: `// @flow + import { map } from 'lodash' +const Component = useRef(() =>
)`, errors: [{ messageId: "memo-required" }], - }, - { - code: `const Component = function Component() { return
; }`, - errors: [{ messageId: "memo-required" }], - }, - { - code: `const Component = useRef(function() { return
; })`, + output: `// @flow +import { memo } from 'react' + import { map } from 'lodash' +const Component = memo(useRef(() =>
))` + }, +// { +// code: `const Component = function Component() { return
; }`, +// errors: [{ messageId: "memo-required" }], +// output: `import { memo } from 'react' +// const Component = memo(function Component() { return
; })` +// }, +// { +// code: `const Component = useRef(function() { return
; })`, +// errors: [{ messageId: "memo-required" }], +// output: `import { memo } from 'react' +// const Component = useRef(memo(function() { return
; }))` +// }, + { + code: `// @flow +import { map } from 'lodash' + +console.warn('Hello World') +function Component() { return
; }`, errors: [{ messageId: "memo-required" }], + output: `// @flow +import { memo } from 'react' +import { map } from 'lodash' + +console.warn('Hello World') +memo(function Component() { return
; })` }, { - code: `function Component() { return
; }`, + code: `import { memo } from 'react' + +function Component() { return
; }`, errors: [{ messageId: "memo-required" }], + output: `import { memo } from 'react' + +memo(function Component() { return
; })` }, // { // filename: "dir/Component.js", // parserOptions: { ecmaVersion: 6, sourceType: "module" }, - // code: `export default function() { return
};`, + // code: export default function() { return
};, // errors: [{ messageId: "memo-required" }], // }, ], diff --git a/__tests__/require-usecallback.ts b/__tests__/require-usecallback.ts index 6c3726e..368fe6e 100644 --- a/__tests__/require-usecallback.ts +++ b/__tests__/require-usecallback.ts @@ -1,5 +1,6 @@ import { RuleTester } from "eslint"; import rule from "../require-usememo"; +import { normalizeIndent } from '../utils'; const ruleTester = new RuleTester({ parser: require.resolve("@typescript-eslint/parser"), @@ -11,114 +12,262 @@ const ruleTester = new RuleTester({ ruleTester.run("useCallback", rule, { valid: [ { - code: `const Component = () => { - const myFn = React.useCallback(function() {}, []); - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myFn = useCallback(function() {}, []); + return ; + } + `, }, { - code: `const Component = () => { - const myFn = useCallback(() => {}, []); - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myFn = useCallback(() => {}, []); + return ; + } + `, }, { - code: `const Component = () => { - const myFn = function() {}; - return
; - }`, + code: normalizeIndent` + const Component = () => { + const myFn = function() {}; + return
; + } + `, }, { - code: `const Component = () => { - const myFn = () => {}; - return
; - }`, + code: normalizeIndent` + const Component = () => { + const myFn = () => {}; + return
; + } + `, }, { - code: ` - const myFn = () => {}; - const Component = () => { - return
; - }`, + code: normalizeIndent` + const myFn = () => {}; + const Component = () => { + return
; + } + `, }, { - code: `const Component = () => { - const myFn1 = useCallback(() => [], []); - const myFn2 = React.useCallback(() => myFn1, [myFn1]); - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myFn1 = useCallback(() => [], []); + const myFn2 = useCallback(() => myFn1, [myFn1]); + return ; + } + `, }, { - code: `const Component = () => { - const myFn = memoize(() => {}); - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myFn = memoize(() => {}); + return ; + } + `, }, { - code: `const Component = () => { - const myFn = lodash.memoize(() => []); - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myFn = lodash.memoize(() => []); + return ; + } + `, }, ], invalid: [ { - code: `const Component = () => { - const myFn = function myFn() {}; - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myFn = function myFn() {}; + return ; + } + `, + // output: normalizeIndent` + // const Component = () => { + // const myFn = useCallback(function() {}, []); + // return ; + // } + // `, errors: [{ messageId: "function-usecallback-props" }], }, { - code: `const Component = () => { - const myFn = () => {}; - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myFn = () => {}; + return ; + } + `, + // output: normalizeIndent` + // const Component = () => { + // const myFn = useCallback(() => {}, []); + // return ; + // } + // `, errors: [{ messageId: "function-usecallback-props" }], }, + // TODO: setup fixer for the following spec (output currently matches code) { - code: `const Component = () => { - let myFn = useCallback(() => ({})); - myFn = () => ({}); - return ; - }`, + code: normalizeIndent` + const Component = () => { + let myFn = useCallback(() => ({})); + myFn = () => ({}); + return ; + } + `, + // output: normalizeIndent` + // const Component = () => { + // let myFn = useCallback(() => ({})); + // myFn = () => ({}); + // return ; + // } + // `, errors: [{ messageId: "usememo-const" }], }, + // TODO: setup fixer for the following spec (output currently matches code) { - code: `const Component = () => { - return {}} />; - }`, + code: normalizeIndent` + const Component = () => { + return {}} />; + } + `, + // output: normalizeIndent` + // const Component = () => { + // return {}} />; + // } + // `, errors: [{ messageId: "function-usecallback-props" }], }, + // TODO: setup fixer for the following spec (output currently matches code) { - code: `const Component = () => { - return []} />; - }`, + code: normalizeIndent` + const Component = () => { + return []} />; + } + `, + // output: normalizeIndent` + // const Component = () => { + // return []} />; + // } + // `, errors: [{ messageId: "function-usecallback-props" }], }, + // // TODO: setup fixer for the following spec (output currently matches code) { - code: `const Component = () => { - const myFn = memoize(() => {}); - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myFn = memoize(() => {}); + return ; + } + `, + // output: normalizeIndent` + // const Component = () => { + // const myFn = memoize(() => {}); + // return ; + // } + // `, options: [{ strict: true }], errors: [{ messageId: "unknown-usememo-props" }], }, + // // TODO: setup fixer for the following spec (output currently matches code) { - code: `const Component = () => { - const myFn = lodash.memoize(() => []); - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myFn = lodash.memoize(() => []); + return ; + } + `, + // output: normalizeIndent` + // const Component = () => { + // const myFn = lodash.memoize(() => []); + // return ; + // } + // `, options: [{ strict: true }], errors: [{ messageId: "unknown-usememo-props" }], }, + // // TODO: setup fixer for the following spec (output currently matches code) { - code: `const Component = () => { - const myFn1 = () => []; - const myFn2 = React.useCallback(() => myFn1, [myFn1]); - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myFn1 = () => []; + const myFn2 = useCallback(() => myFn1, [myFn1]); + return ; + } + `, + // output: normalizeIndent` + // const Component = () => { + // const myFn1 = () => []; + // const myFn2 = useCallback(() => myFn1, [myFn1]); + // return ; + // } + // `, errors: [{ messageId: "function-usecallback-deps" }], }, + // { + // code: normalizeIndent` + // // @flow + // import { d2Uri } from 'd2/utils/Routes' + // import { prettyNumber } from '@vydia/js-core' + // import { useHistory } from 'react-router' + // import { useIsLabel } from 'd2/hooks/useIsLabel' + // import { useOrganizationTotalConflictsBoxQuery, useUserTotalConflictsBoxQuery } from './queries' + // import SummaryBox from 'd2/components/SummaryBox' + // import useTranslations from './translations' + // import type { StatelessFunctionalComponent } from 'react' + + // const TotalConflictsBox: StatelessFunctionalComponent<{}> = () => { + // const [isLabel] = useIsLabel() + // const [organizationData] = useOrganizationTotalConflictsBoxQuery({ isLabel }) + // const [userData] = useUserTotalConflictsBoxQuery({ isLabel }) + // const t = useTranslations() + // const history = useHistory() + + // const data = isLabel ? organizationData : userData + // return ( history.push(d2Uri('/insights/conflicts'))} + // testID='WidgetDashboard-TotalConflictsBox' + // title={isLabel ? t.labelTotalConflicts : t.userTotalConflicts} + // value={data && prettyNumber(data.totalConflicts)} + // />) + // } + + // export default TotalConflictsBox + // `, + // output: normalizeIndent` + // // @flow + // import { d2Uri } from 'd2/utils/Routes' + // import { prettyNumber } from '@vydia/js-core' + // import { useHistory } from 'react-router' + // import { useIsLabel } from 'd2/hooks/useIsLabel' + // import { useOrganizationTotalConflictsBoxQuery, useUserTotalConflictsBoxQuery } from './queries' + // import SummaryBox from 'd2/components/SummaryBox' + // import useTranslations from './translations' + // import type { StatelessFunctionalComponent } from 'react' + + // const TotalConflictsBox: StatelessFunctionalComponent<{}> = () => { + // const [isLabel] = useIsLabel() + // const [organizationData] = useOrganizationTotalConflictsBoxQuery({ isLabel }) + // const [userData] = useUserTotalConflictsBoxQuery({ isLabel }) + // const t = useTranslations() + // const history = useHistory() + + // const data = isLabel ? organizationData : userData + // return ( history.push(d2Uri('/insights/conflicts'))} + // testID='WidgetDashboard-TotalConflictsBox' + // title={isLabel ? t.labelTotalConflicts : t.userTotalConflicts} + // value={data && prettyNumber(data.totalConflicts)} + // />) + // } + + // export default TotalConflictsBox + // `, + // errors: [{ messageId: "function-usecallback-props"}] + // } ], }); diff --git a/__tests__/require-usememo-children.ts b/__tests__/require-usememo-children.ts index ec7c8f5..696e246 100644 --- a/__tests__/require-usememo-children.ts +++ b/__tests__/require-usememo-children.ts @@ -12,7 +12,7 @@ ruleTester.run("useMemo children", rule, { valid: [ { code: `const Component = () => { - const children = React.useMemo(() =>
, []); + const children = useMemo(() =>
, []); return {children}; }`, }, @@ -23,7 +23,7 @@ ruleTester.run("useMemo children", rule, { }, { code: `const Component = () => { - const renderFn = React.useCallback(() =>
, []); + const renderFn = useCallback(() =>
, []); return {renderFn}; }`, }, @@ -31,7 +31,7 @@ ruleTester.run("useMemo children", rule, { invalid: [ { code: `const Component = () => { - const children = React.useMemo(() =>
, []); + const children = useMemo(() =>
, []); return <> {children} diff --git a/__tests__/require-usememo.ts b/__tests__/require-usememo.ts index cbe60de..856dc8b 100644 --- a/__tests__/require-usememo.ts +++ b/__tests__/require-usememo.ts @@ -1,5 +1,6 @@ import { RuleTester } from "eslint"; import rule from "../require-usememo"; +import { normalizeIndent } from '../utils'; const ruleTester = new RuleTester({ parser: require.resolve("@typescript-eslint/parser"), @@ -11,134 +12,239 @@ const ruleTester = new RuleTester({ ruleTester.run("useMemo", rule, { valid: [ { - code: `const Component = () => { - const myObject = React.useMemo(() => ({}), []); - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myObject = useMemo(() => ({}), []); + return ; + } + `, }, { - code: `const Component = () => { - const myArray = useMemo(() => [], []); - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myArray = useMemo(() => [], []); + return ; + } + `, }, { - code: `const Component = () => { - const myArray = React.useMemo(() => new Object(), []); - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myArray = useMemo(() => new Object(), []); + return ; + } + `, }, { - code: `const Component = () => { - const myObject = {}; - return
; - }`, + code: normalizeIndent` + const Component = () => { + const myObject = {}; + return
; + } + `, }, { - code: `const Component = () => { - const myArray = []; - return
; - }`, + code: normalizeIndent` + const Component = () => { + const myArray = []; + return
; + } + `, }, { - code: `const Component = () => { - const myNumber1 = 123; - const myNumber2 = 123 + 456; - const myString1 = 'abc'; - const myString2 = \`abc\`; - return
; - }`, + code: normalizeIndent` + const Component = () => { + const myNumber1 = 123; + const myNumber2 = 123 + 456; + const myString1 = 'abc'; + const myString2 = \`abc\`; + return
; + } + `, }, { - code: `const Component = () => { - const myObject = memoize({}); - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myObject = memoize({}); + return ; + } + `, }, { - code: `const Component = () => { - const myArray = lodash.memoize([]); - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myArray = lodash.memoize([]); + return ; + } + `, }, { - code: `const Component = () => { - const myComplexString = css\`color: red;\`; - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myComplexString = css\`color: red;\`; + return ; + } + `, }, ], invalid: [ { - code: `const Component = () => { - const myObject = {}; - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myObject = {}; + return ; + } + `, + // output: normalizeIndent` + // const Component = () => { + // const myObject = useMemo(() => ({}), []); + // return ; + // } + // `, errors: [{ messageId: "object-usememo-props" }], }, { - code: `const Component = () => { - const myArray = []; - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myArray = []; + return ; + } + `, + // output: normalizeIndent` + // const Component = () => { + // const myArray = useMemo(() => [], []); + // return ; + // } + // `, errors: [{ messageId: "array-usememo-props" }], }, { - code: `const Component = () => { - const myInstance = new Object(); - return ; - }`, + code: normalizeIndent` + const Component = () => { + const myInstance = new Object(); + return ; + } + `, + // output: normalizeIndent` + // const Component = () => { + // const myInstance = useMemo(() => new Object(), []); + // return ; + // } + // `, errors: [{ messageId: "instance-usememo-props" }], }, - { - code: `const Component = () => { - let myObject = useMemo({}); - myObject = {a: 'b'}; - return ; - }`, + // TODO: setup fixer for the following spec (output currently matches code) + { + code: normalizeIndent` + const Component = () => { + let myObject = useMemo({}); + myObject = {a: 'b'}; + return ; + } + `, + // output: normalizeIndent` + // const Component = () => { + // let myObject = useMemo({}); + // myObject = {a: 'b'}; + // return ; + // } + // `, errors: [{ messageId: "usememo-const" }], }, - { - code: `const Component = () => { - return ; - }`, + // TODO: setup fixer for the following spec (output currently matches code) + { + code: normalizeIndent` + const Component = () => { + return ; + } + `, + // output: normalizeIndent` + // const Component = () => { + // return ; + // } + // `, errors: [{ messageId: "object-usememo-props" }], }, - { - code: `const Component = () => { - return ; - }`, + // TODO: setup fixer for the following spec (output currently matches code) + { + code: normalizeIndent` + const Component = () => { + return ; + } + `, + // output: normalizeIndent` + // const Component = () => { + // return ; + // } + // `, errors: [{ messageId: "array-usememo-props" }], }, - { - code: `const Component = () => { - const myObject = memoize({}); - return ; - }`, + // TODO: setup fixer for the following spec (output currently matches code) + { + code: normalizeIndent` + const Component = () => { + const myObject = memoize({}); + return ; + } + `, + // output: normalizeIndent` + // const Component = () => { + // const myObject = memoize({}); + // return ; + // } + // `, options: [{ strict: true }], errors: [{ messageId: "unknown-usememo-props" }], }, + // TODO: setup fixer for the following spec (output currently matches code) { - code: `const Component = () => { - const myArray = lodash.memoize([]); + code: normalizeIndent` + const Component = () => { + const myArray = lodash.memoize([]); return ; - }`, + } + `, + // output: normalizeIndent` + // const Component = () => { + // const myArray = lodash.memoize([]); + // return ; + // } + // `, options: [{ strict: true }], errors: [{ messageId: "unknown-usememo-props" }], }, - { - code: `const Component = () => { - const myArray1 = []; - const myArray2 = React.useMemo(() => myArray1, [myArray1]); - return ; - }`, + // TODO: setup fixer for the following spec (output currently matches code) + { + code: normalizeIndent` + const Component = () => { + const myArray1 = []; + const myArray2 = useMemo(() => myArray1, [myArray1]); + return ; + } + `, + // output: normalizeIndent` + // const Component = () => { + // const myArray1 = []; + // const myArray2 = useMemo(() => myArray1, [myArray1]); + // return ; + // } + // `, errors: [{ messageId: "array-usememo-deps" }], }, - { - code: `const Component = () => { - const myComplexString = css\`color: red;\`; - return ; - }`, + // TODO: setup fixer for the following spec (output currently matches code) + { + code: normalizeIndent` + const Component = () => { + const myComplexString = css\`color: red;\`; + return ; + } + `, + // output: normalizeIndent` + // const Component = () => { + // const myComplexString = css\`color: red;\`; + // return ; + // } + // `, options: [{ strict: true }], errors: [{ messageId: "unknown-usememo-props" }], }, diff --git a/common.ts b/common.ts index 4512d15..4fb0bc2 100644 --- a/common.ts +++ b/common.ts @@ -61,7 +61,7 @@ export function getExpressionMemoStatus( context: Rule.RuleContext, expression: TSESTree.Expression ): MemoStatus { - switch (expression.type) { + switch (expression?.type) { case "ObjectExpression": return MemoStatus.UnmemoizedObject; case "ArrayExpression": diff --git a/package.json b/package.json index 471d2f5..e62ba0a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-react-memo", - "version": "0.0.3", + "version": "0.0.11", "description": "", "main": "dist/index.js", "author": "Stefano J. Attardi ", @@ -14,9 +14,11 @@ "@rollup/plugin-typescript": "^8.2.1", "@types/eslint": "^7.2.7", "@types/jest": "^26.0.22", + "@types/lodash": "^4.14.175", "@typescript-eslint/parser": "^4.19.0", - "@typescript-eslint/types": "^4.19.0", + "@typescript-eslint/types": "^5.0.0", "eslint": "^7.23.0", + "gitpkg": "^1.0.0-beta.2", "jest": "^25.0.0", "rollup": "^2.43.1", "ts-jest": "^26.5.4", @@ -24,11 +26,23 @@ }, "scripts": { "test": "jest", + "test-debug": "node --inspect-brk node_modules/.bin/jest --watch", + "test-watch": "jest --watch", "build": "rm -rf dist && rollup -c", + "build-and-watch": "rm -rf dist && rollup -c --watch", "prepublish:public": "npm run build && npm run bump-version", - "publish:public": "npm publish --access public" + "publish:public": "npm publish --access public", + "deploy": "yarn build && yarn publish-git", + "publish-git": "yarn version-bump && gitpkg publish", + "link-to-web": "cd ../web && yarn link-eslint-plugin-react-memo-auto && cd ../eslint-plugin-react-memo && yarn build-and-watch", + "link-prepare": "yarn install && yarn link && echo 'Now run \"yarn link-eslint-plugin-react-memo\" in mobile and web. And make sure you are running \"yarn build-and-watch\" to keep those dist folders available.'", + "unlink-prepare": "yarn install && yarn unlink && echo 'Now run \"yarn unlink-eslint-plugin-react-memo\" in mobile and web. And make sure you are running \"yarn build-and-watch\" to keep those dist folders available.'", + "version-bump": "npm version patch && git add . && git commit --allow-empty -m \"version-bump\"" }, "files": [ "dist" - ] + ], + "dependencies": { + "typescript-eslint": "^0.0.1-alpha.0" + } } diff --git a/require-memo.ts b/require-memo.ts index 8209011..f37e725 100644 --- a/require-memo.ts +++ b/require-memo.ts @@ -3,6 +3,7 @@ import * as ESTree from "estree"; import * as path from "path"; const componentNameRegex = /^[^a-z]/; +const memoImportText = 'import { memo } from \'react\'\n' function isMemoCallExpression(node: Rule.Node) { if (node.type !== "CallExpression") return false; @@ -32,7 +33,8 @@ function checkFunction( | ESTree.FunctionExpression | ESTree.FunctionDeclaration ) & - Rule.NodeParentExtension + Rule.NodeParentExtension, + alreadyImportedMemo: boolean ) { let currentNode = node.parent; while (currentNode.type === "CallExpression") { @@ -47,7 +49,52 @@ function checkFunction( const { id } = currentNode; if (id.type === "Identifier") { if (componentNameRegex.test(id.name)) { - context.report({ node, messageId: "memo-required" }); + context.report({ node, messageId: "memo-required", fix: (fixer): Rule.Fix | null => { + // @ts-ignore + const parent = node.parent + let scope + if (parent.type === 'VariableDeclarator') { + scope = node + } else { + scope = parent + } + + const sourceCode = context.getSourceCode(); + + const getIndexToInsertImport = () => { + const allComments = sourceCode.getAllComments() + let insertImportLoc = 1 + for (let i = 0, l = allComments.length; i < l; i++) { + const comment = allComments[i] + // @ts-ignore + const commentIsBackToBackWithPrev = comment.loc.start.line <= insertImportLoc + 1 + + if (!commentIsBackToBackWithPrev) break + // @ts-ignore + insertImportLoc = comment.loc.end.line + } + try { + return sourceCode.getIndexFromLoc({ line: insertImportLoc + 1, column: 0 }) + } catch { + null + } + } + + const importIndex = getIndexToInsertImport() + const text = sourceCode.getText(scope); + // @ts-ignore + const fullSourceText = sourceCode.getText(); + + let fixedCode = `memo(${text})` + if (text.startsWith('useRef(function')) { + fixedCode = `useRef(${text.replace('useRef', 'memo')})` + } + // @ts-ignore + return [ + importIndex && !alreadyImportedMemo ? fixer.insertTextAfterRange([importIndex, importIndex], memoImportText) : null, + fixer.replaceText(scope, fixedCode), + ].filter(i => i) + } }); } } } else if ( @@ -55,7 +102,40 @@ function checkFunction( currentNode.type === "Program" ) { if (node.id !== null && componentNameRegex.test(node.id.name)) { - context.report({ node, messageId: "memo-required" }); + context.report({ node, messageId: "memo-required", fix: (fixer): Rule.Fix => { + let scope = node + const sourceCode = context.getSourceCode(); + + const getIndexToInsertImport = () => { + const allComments = sourceCode.getAllComments() + let insertImportLoc = 1 + for (let i = 0, l = allComments.length; i < l; i++) { + const comment = allComments[i] + // @ts-ignore + const commentIsBackToBackWithPrev = comment.loc.start.line <= insertImportLoc + 1 + + if (!commentIsBackToBackWithPrev) break + // @ts-ignore + insertImportLoc = comment.loc.end.line + } + try { + return sourceCode.getIndexFromLoc({ line: insertImportLoc + 1, column: 0 }) + } catch { + null + } + } + + const importIndex = getIndexToInsertImport() + + const text = sourceCode.getText(scope); + const fullSourceText = sourceCode.getText(); + let fixedCode = `memo(${text})` + // @ts-ignore + return [ + importIndex && !alreadyImportedMemo ? fixer.insertTextAfterRange([importIndex, importIndex], memoImportText) : null, + fixer.replaceText(node, fixedCode), + ].filter(i => i) + } }); } else { if (context.getFilename() === "") return; const filename = path.basename(context.getFilename()); @@ -68,21 +148,38 @@ function checkFunction( const rule: Rule.RuleModule = { meta: { + fixable: 'code', messages: { "memo-required": "Component definition not wrapped in React.memo()", }, }, - create: (context) => ({ - ArrowFunctionExpression(node) { - checkFunction(context, node); - }, - FunctionDeclaration(node) { - checkFunction(context, node); - }, - FunctionExpression(node) { - checkFunction(context, node); - }, - }), + create: (context) => { + let alreadyImportedMemo = false + + return { + ImportDeclaration (node) { + if (alreadyImportedMemo) return + + if (node.source.value === 'react') { + const specifiers = node.specifiers + for (let i = 0, l = specifiers.length; i < l && !alreadyImportedMemo; i++) { + // @ts-ignore + const name = specifiers[i]?.imported?.name + if (name === 'memo') alreadyImportedMemo = true + } + } + }, + ArrowFunctionExpression(node) { + checkFunction(context, node, alreadyImportedMemo); + }, + FunctionDeclaration(node) { + checkFunction(context, node, alreadyImportedMemo); + }, + FunctionExpression(node) { + checkFunction(context, node, alreadyImportedMemo); + }, + } + }, }; export default rule; diff --git a/require-usememo-children.ts b/require-usememo-children.ts index 209a3d5..e1ccb47 100644 --- a/require-usememo-children.ts +++ b/require-usememo-children.ts @@ -7,9 +7,6 @@ import { MemoStatus, } from "./common"; -const componentNameRegex = /^[^a-z]/; -const hookNameRegex = /^use[A-Z0-9].*$/; - const messages = { "object-usememo-children": "Object literal should be wrapped in React.useMemo() when used as children", @@ -30,6 +27,7 @@ const messages = { const rule: Rule.RuleModule = { meta: { messages, + fixable: 'code', schema: [ { type: "object", @@ -58,7 +56,7 @@ const rule: Rule.RuleModule = { } if (child.type === "JSXExpressionContainer") { const { expression } = child; - if (expression.type !== "JSXEmptyExpression") { + if (expression?.type !== "JSXEmptyExpression") { switch (getExpressionMemoStatus(context, expression)) { case MemoStatus.UnmemoizedObject: report(node, "object-usememo-children"); diff --git a/require-usememo.ts b/require-usememo.ts index 7702d72..28606d5 100644 --- a/require-usememo.ts +++ b/require-usememo.ts @@ -1,29 +1,15 @@ import { Rule } from "eslint"; import * as ESTree from "estree"; import { TSESTree } from "@typescript-eslint/types"; +import { Node } from "@typescript-eslint/types/dist/ast-spec" +import { isArrowFn, isHook } from "./utils"; + import { getExpressionMemoStatus, isComplexComponent, MemoStatus, } from "./common"; -const hookNameRegex = /^use[A-Z0-9].*$/; - -function isHook(node: TSESTree.Node) { - if (node.type === "Identifier") { - return hookNameRegex.test(node.name); - } else if ( - node.type === "MemberExpression" && - !node.computed && - isHook(node.property) - ) { - const obj = node.object; - return obj.type === "Identifier" && obj.name === "React"; - } else { - return false; - } -} - const messages = { "object-usememo-props": "Object literal should be wrapped in React.useMemo() when used as a prop", @@ -55,6 +41,7 @@ const messages = { const rule: Rule.RuleModule = { meta: { + fixable: 'code', messages, schema: [ { @@ -69,27 +56,56 @@ const rule: Rule.RuleModule = { context.report({ node, messageId: messageId as string }); } + const useMemoFix = (fixer: Rule.RuleFixer, implicitReturn: boolean = true): Rule.Fix | null => { + const sourceCode = context.getSourceCode(); + const references = context.getScope()?.references + const filteredRefs = references?.filter((reference) => reference?.writeExpr) + // @ts-ignore + const definition = filteredRefs?.[0]?.writeExpr?.parent + if (!definition) return null + const [name, value] = sourceCode.getText(definition).split(/=(.+)/) + const fixedCode = `${name.trim()} = useMemo(() => ${implicitReturn ? value.trim() : `(${value.trim()})`}, [])` + return fixer.replaceText(definition, fixedCode) + } + + const useCallbackFix = (fixer: Rule.RuleFixer): Rule.Fix | null => { + let fixedCode = '' + const sourceCode = context.getSourceCode(); + const references = context.getScope()?.references + const filteredRefs = references?.filter((reference) => reference?.writeExpr) + // @ts-ignore + const definition = filteredRefs?.[0]?.writeExpr?.parent + if (!definition) return null + const [name, value] = sourceCode.getText(definition).split(/=(.+)/) + if(isArrowFn(value)){ + fixedCode = `${name.trim()} = useCallback(${value.trim()}, [])` + } else { + fixedCode = `${name.trim()} = useCallback(${value.replace(`function ${name.trim()}`, 'function').trim()}, [])` + } + return fixer.replaceText(definition, fixedCode) + } + return { - JSXAttribute: (node: ESTree.Node & Rule.NodeParentExtension) => { + JSXAttribute: (node: Rule.Node & Rule.NodeParentExtension) => { const { parent, value } = (node as unknown) as TSESTree.JSXAttribute & Rule.NodeParentExtension; if (value === null) return; if (!isComplexComponent(parent)) return; if (value.type === "JSXExpressionContainer") { const { expression } = value; - if (expression.type !== "JSXEmptyExpression") { + if (expression?.type !== "JSXEmptyExpression") { switch (getExpressionMemoStatus(context, expression)) { case MemoStatus.UnmemoizedObject: - report(node, "object-usememo-props"); + context.report({ node, messageId: "object-usememo-props" }); break; case MemoStatus.UnmemoizedArray: - report(node, "array-usememo-props"); + context.report({ node, messageId: "array-usememo-props" }); break; case MemoStatus.UnmemoizedNew: - report(node, "instance-usememo-props"); + context.report({ node, messageId: "instance-usememo-props" }); break; case MemoStatus.UnmemoizedFunction: - report(node, "function-usecallback-props"); + context.report({ node, messageId: "function-usecallback-props" }); break; case MemoStatus.UnmemoizedFunctionCall: case MemoStatus.UnmemoizedOther: diff --git a/utils/index.ts b/utils/index.ts new file mode 100644 index 0000000..b530bcf --- /dev/null +++ b/utils/index.ts @@ -0,0 +1,38 @@ +import { TSESTree } from "@typescript-eslint/types"; + +export function normalizeIndent(strings: TemplateStringsArray) { + const codeLines = strings[0].split('\n'); + const match = codeLines[1].match(/\s+/); + const leftPadding = match ? match[0].length : 0; + return codeLines.map(line => line.substr(leftPadding)).join('\n'); +} + +export function isArrowFn(fn: string) { return /^[^{]+?=>/.test(fn.toString()); }; + +export const hookNames: string[] = [ + 'useState', + 'useEffect', + 'useContext', + 'useReducer', + 'useCallback', + 'useMemo', + 'useRef', + 'useImperativeHandle', + 'useLayoutEffect', + 'useDebugValue', +] + +export function isHook(node: TSESTree.Node) { + if (node.type === "Identifier") { + return Boolean(hookNames.find(a => a.includes(node.name))); + } else if ( + node.type === "MemberExpression" && + !node.computed && + isHook(node.property) + ) { + const obj = node.object; + return obj.type === "Identifier" && obj.name === "React"; + } else { + return false; + } +} diff --git a/yarn.lock b/yarn.lock index d005058..52e642b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -615,6 +615,14 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== +"@types/glob@^7.1.1": + version "7.1.4" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.4.tgz#ea59e21d2ee5c517914cb4bc8e4153b99e566672" + integrity sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + "@types/graceful-fs@^4.1.2": version "4.1.5" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" @@ -662,6 +670,16 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== +"@types/lodash@^4.14.175": + version "4.14.175" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.175.tgz#b78dfa959192b01fae0ad90e166478769b215f45" + integrity sha512-XmdEOrKQ8a1Y/yxQFOMbC47G/V2VDO1GvMRnl4O75M4GW/abC5tnfzadQYkqEveqRM1dEJGFFegfPNA2vvx2iw== + +"@types/minimatch@*": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== + "@types/node@*": version "14.14.37" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.37.tgz#a3dd8da4eb84a996c36e331df98d82abd76b516e" @@ -719,11 +737,16 @@ "@typescript-eslint/types" "4.19.0" "@typescript-eslint/visitor-keys" "4.19.0" -"@typescript-eslint/types@4.19.0", "@typescript-eslint/types@^4.19.0": +"@typescript-eslint/types@4.19.0": version "4.19.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.19.0.tgz#5181d5d2afd02e5b8f149ebb37ffc8bd7b07a568" integrity sha512-A4iAlexVvd4IBsSTNxdvdepW0D4uR/fwxDrKUa+iEY9UWvGREu2ZyB8ylTENM1SH8F7bVC9ac9+si3LWNxcBuA== +"@typescript-eslint/types@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.0.0.tgz#25d93f6d269b2d25fdc51a0407eb81ccba60eb0f" + integrity sha512-dU/pKBUpehdEqYuvkojmlv0FtHuZnLXFBn16zsDmlFF3LXkOpkAQ2vrKc3BidIIve9EMH2zfTlxqw9XM0fFN5w== + "@typescript-eslint/typescript-estree@4.19.0": version "4.19.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.19.0.tgz#8a709ffa400284ab72df33376df085e2e2f61147" @@ -778,6 +801,14 @@ acorn@^7.1.0, acorn@^7.4.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -998,6 +1029,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -1018,6 +1054,20 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +bl@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -1091,6 +1141,14 @@ buffer-from@1.x, buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + builtin-modules@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887" @@ -1138,7 +1196,7 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -chalk@^2.0.0: +chalk@^2.0.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1163,6 +1221,11 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" @@ -1178,6 +1241,23 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-spinners@^2.2.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" + integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== + cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -1187,6 +1267,11 @@ cliui@^6.0.0: strip-ansi "^6.0.0" wrap-ansi "^6.2.0" +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -1355,6 +1440,13 @@ deepmerge@^4.2.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" @@ -1377,6 +1469,20 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" +del@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7" + integrity sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA== + dependencies: + globby "^10.0.1" + graceful-fs "^4.2.2" + is-glob "^4.0.1" + is-path-cwd "^2.2.0" + is-path-inside "^3.0.1" + p-map "^3.0.0" + rimraf "^3.0.0" + slash "^3.0.0" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -1436,7 +1542,7 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -end-of-stream@^1.1.0: +end-of-stream@^1.1.0, end-of-stream@^1.4.1, end-of-stream@^1.4.4: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -1634,6 +1740,21 @@ execa@^3.2.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" +execa@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -1713,6 +1834,17 @@ fast-deep-equal@^3.1.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-glob@^3.0.3: + version "3.2.7" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" + integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-glob@^3.1.1: version "3.2.5" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" @@ -1820,6 +1952,11 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1881,7 +2018,39 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -glob-parent@^5.0.0, glob-parent@^5.1.0: +git-remote-origin-url@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/git-remote-origin-url/-/git-remote-origin-url-3.1.0.tgz#c90c1cb0f66658566bbc900509ab093a1522d2b3" + integrity sha512-yVSfaTMO7Bqk6Xx3696ufNfjdrajX7Ig9GuAeO2V3Ji7stkDoBNFldnWIAsy0qviUd0Z+X2P6ziJENKztW7cBQ== + dependencies: + gitconfiglocal "^2.1.0" + +gitconfiglocal@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/gitconfiglocal/-/gitconfiglocal-2.1.0.tgz#07c28685c55cc5338b27b5acbcfe34aeb92e43d1" + integrity sha512-qoerOEliJn3z+Zyn1HW2F6eoYJqKwS6MgC9cztTLUB/xLWX8gD/6T60pKn4+t/d6tP7JlybI7Z3z+I572CR/Vg== + dependencies: + ini "^1.3.2" + +gitpkg@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gitpkg/-/gitpkg-1.0.0-beta.2.tgz#afb8cc99fc38ebe60497d35ea13d323fc88377e8" + integrity sha512-ASD0wK+xDx/mPWwasUIKD6o0gKCwhY1KyfNkeTjmjMXHNGMTz1I344D4V+ndFlZPdUccdrMyxHD7XB99+Kl7Ag== + dependencies: + bluebird "^3.7.2" + chalk "^3.0.0" + del "^5.1.0" + end-of-stream "^1.4.4" + execa "^4.0.0" + find-up "^4.1.0" + git-remote-origin-url "^3.1.0" + make-dir "^3.0.2" + ora "^4.0.3" + semver "^7.1.3" + tar-fs "^2.0.1" + yargs "^15.3.1" + +glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -1919,6 +2088,20 @@ globals@^13.6.0: dependencies: type-fest "^0.20.2" +globby@^10.0.1: + version "10.0.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543" + integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg== + dependencies: + "@types/glob" "^7.1.1" + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.0.3" + glob "^7.1.3" + ignore "^5.1.1" + merge2 "^1.2.3" + slash "^3.0.0" + globby@^11.0.1: version "11.0.3" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.3.tgz#9b1f0cb523e171dd1ad8c7b2a9fb4b644b9593cb" @@ -1931,6 +2114,11 @@ globby@^11.0.1: merge2 "^1.3.0" slash "^3.0.0" +graceful-fs@^4.2.2: + version "4.2.8" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== + graceful-fs@^4.2.4: version "4.2.6" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" @@ -2040,12 +2228,17 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.4: +ignore@^5.1.1, ignore@^5.1.4: version "5.1.8" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== @@ -2071,6 +2264,11 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -2079,11 +2277,16 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2: +inherits@2, inherits@^2.0.3, inherits@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +ini@^1.3.2: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + ip-regex@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" @@ -2198,6 +2401,11 @@ is-glob@^4.0.0, is-glob@^4.0.1: dependencies: is-extglob "^2.1.1" +is-interactive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" + integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== + is-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" @@ -2215,6 +2423,16 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-path-cwd@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + +is-path-inside@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -2882,6 +3100,13 @@ lodash@4.x, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +log-symbols@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" + integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== + dependencies: + chalk "^2.4.2" + lolex@^5.0.0: version "5.1.2" resolved "https://registry.yarnpkg.com/lolex/-/lolex-5.1.2.tgz#953694d098ce7c07bc5ed6d0e42bc6c0c6d5a367" @@ -2896,7 +3121,7 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -make-dir@^3.0.0: +make-dir@^3.0.0, make-dir@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== @@ -2932,7 +3157,7 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.3.0: +merge2@^1.2.3, merge2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== @@ -2964,6 +3189,14 @@ micromatch@^4.0.2: braces "^3.0.1" picomatch "^2.0.5" +micromatch@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + mime-db@1.46.0: version "1.46.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.46.0.tgz#6267748a7f799594de3cbc8cde91def349661cee" @@ -3001,6 +3234,11 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" +mkdirp-classic@^0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + mkdirp@1.x: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" @@ -3016,6 +3254,11 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -3176,6 +3419,20 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" +ora@^4.0.3: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ora/-/ora-4.1.1.tgz#566cc0348a15c36f5f0e979612842e02ba9dddbc" + integrity sha512-sjYP8QyVWBpBZWD6Vr1M/KwknSw6kJOz41tvGMlwWeClHBtYKTbHMki1PsLZnxKpXMPbTKv9b3pjQu3REib96A== + dependencies: + chalk "^3.0.0" + cli-cursor "^3.1.0" + cli-spinners "^2.2.0" + is-interactive "^1.0.0" + log-symbols "^3.0.0" + mute-stream "0.0.8" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + p-each-series@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" @@ -3205,6 +3462,13 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-map@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" + integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== + dependencies: + aggregate-error "^3.0.0" + p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -3277,6 +3541,11 @@ picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1, picomatch@^2.2.2: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== +picomatch@^2.2.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== + pirates@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" @@ -3401,6 +3670,15 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" +readable-stream@^3.1.1, readable-stream@^3.4.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + realpath-native@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-2.0.0.tgz#7377ac429b6e1fd599dc38d08ed942d0d7beb866" @@ -3526,6 +3804,14 @@ resolve@^1.10.0, resolve@^1.17.0, resolve@^1.19.0: is-core-module "^2.2.0" path-parse "^1.0.6" +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" @@ -3562,7 +3848,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-buffer@^5.0.1, safe-buffer@^5.1.2: +safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -3611,7 +3897,7 @@ saxes@^3.1.9: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@7.x, semver@^7.2.1, semver@^7.3.2: +semver@7.x, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== @@ -3850,6 +4136,13 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -3921,6 +4214,27 @@ table@^6.0.4: slice-ansi "^4.0.0" string-width "^4.2.0" +tar-fs@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" + integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" + +tar-stream@^2.1.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + terminal-link@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" @@ -4100,6 +4414,11 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" +typescript-eslint@^0.0.1-alpha.0: + version "0.0.1-alpha.0" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-0.0.1-alpha.0.tgz#285d68a4e96588295cd436278801bcb6a6b916c1" + integrity sha512-1hNKM37dAWML/2ltRXupOq2uqcdRQyDFphl+341NTPXFLLLiDhErXx8VtaSLh3xP7SyHZdcCgpt9boYYVb3fQg== + typescript@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3" @@ -4140,6 +4459,11 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" @@ -4199,6 +4523,13 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.x" +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + dependencies: + defaults "^1.0.3" + webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"