Merge pull request #3176 from ethereum/codeformat

Codeformat
pull/5370/head
yann300 2 years ago committed by GitHub
commit 2ebc6eadb1
  1. 147
      apps/remix-ide-e2e/src/tests/code_format.test.ts
  2. 10
      apps/remix-ide-e2e/src/tests/plugin_api.ts
  3. 2
      apps/remix-ide-e2e/src/tests/workspace.test.ts
  4. 210
      apps/remix-ide/src/app/plugins/code-format.ts
  5. 44
      libs/remix-ws-templates/src/templates/blank/.prettierrc
  6. 7
      libs/remix-ws-templates/src/templates/blank/index.ts
  7. 44
      libs/remix-ws-templates/src/templates/gnosisSafeMultisig/.prettierrc
  8. 4
      libs/remix-ws-templates/src/templates/gnosisSafeMultisig/index.ts
  9. 44
      libs/remix-ws-templates/src/templates/ozerc1155/.prettierrc
  10. 6
      libs/remix-ws-templates/src/templates/ozerc1155/index.ts
  11. 44
      libs/remix-ws-templates/src/templates/ozerc20/.prettierrc
  12. 6
      libs/remix-ws-templates/src/templates/ozerc20/index.ts
  13. 44
      libs/remix-ws-templates/src/templates/ozerc721/.prettierrc
  14. 4
      libs/remix-ws-templates/src/templates/ozerc721/index.ts
  15. 44
      libs/remix-ws-templates/src/templates/remixDefault/.prettierrc
  16. 2
      libs/remix-ws-templates/src/templates/remixDefault/index.ts
  17. 44
      libs/remix-ws-templates/src/templates/zeroxErc20/.prettierrc
  18. 6
      libs/remix-ws-templates/src/templates/zeroxErc20/index.ts
  19. 2
      package.json
  20. 5
      workspace.json
  21. 7
      yarn.lock

@ -0,0 +1,147 @@
'use strict'
import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
'open default prettier config and set the content': function (browser: NightwatchBrowser) {
browser.openFile('.prettierrc.json').pause(1000).setEditorValue(
JSON.stringify(defaultPrettierOptions, null, '\t')
)
},
'Add Ballot': function (browser: NightwatchBrowser) {
browser
.addFile('Untitled.sol', { content: unformattedContract })
},
'Should put cursor at "unfomattedContract"': function (browser: NightwatchBrowser) {
const path = "//*[@class='view-line' and contains(.,'unfomattedContract')]"
browser.waitForElementVisible('#editorView')
.click({
locateStrategy: 'xpath',
selector: path
})
},
'Format code': function (browser: NightwatchBrowser) {
browser
.perform(function () {
const actions = this.actions({ async: true });
return actions
.keyDown(this.Keys.SHIFT)
.keyDown(this.Keys.ALT)
.sendKeys('f')
}).pause(2000)
.getEditorValue(function (result: string) {
browser.assert.equal(result.trim(), formattedContract)
})
},
'open default prettier config and change the value of tabWdith': function (browser: NightwatchBrowser) {
browser.openFile('.prettierrc.json').pause(1000)
.getEditorValue(function (result: string) {
result = result.replace(/4/g, '2')
browser.setEditorValue(result)
}).pause(4000)
},
'Should put cursor at "unfomattedContract" again': function (browser: NightwatchBrowser) {
browser.openFile('Untitled.sol')
const path = "//*[@class='view-line' and contains(.,'unfomattedContract')]"
browser.waitForElementVisible('#editorView')
.click({
locateStrategy: 'xpath',
selector: path
})
},
'Format code with 2 tabWidth': function (browser: NightwatchBrowser) {
browser
.perform(function () {
const actions = this.actions({ async: true });
return actions
.keyDown(this.Keys.SHIFT)
.keyDown(this.Keys.ALT)
.sendKeys('f')
}).pause(2000)
.getEditorValue(function (result: string) {
browser.assert.equal(result.trim(), formattedWithTabWidth2)
})
}
}
const unformattedContract = `pragma solidity >=0.4.22 <0.9.0;
contract unfomattedContract {
bytes32[] proposalNames;
function beforeAll () public {
proposalNames.push(bytes32("candidate1"));
ballotToTest = new Ballot(proposalNames);
}
}`
const formattedContract = `pragma solidity >=0.4.22 <0.9.0;
contract unfomattedContract {
bytes32[] proposalNames;
function beforeAll() public {
proposalNames.push(bytes32("candidate1"));
ballotToTest = new Ballot(proposalNames);
}
}`
const formattedWithTabWidth2 = `pragma solidity >=0.4.22 <0.9.0;
contract unfomattedContract {
bytes32[] proposalNames;
function beforeAll() public {
proposalNames.push(bytes32("candidate1"));
ballotToTest = new Ballot(proposalNames);
}
}`
const defaultPrettierOptions = {
"overrides": [
{
"files": "*.sol",
"options": {
"printWidth": 80,
"tabWidth": 4,
"useTabs": false,
"singleQuote": false,
"bracketSpacing": false
}
},
{
"files": "*.yml",
"options": {
}
},
{
"files": "*.yaml",
"options": {
}
},
{
"files": "*.toml",
"options": {
}
},
{
"files": "*.json",
"options": {
}
},
{
"files": "*.js",
"options": {
}
},
{
"files": "*.ts",
"options": {
}
}
]
}

@ -234,7 +234,8 @@ module.exports = {
contracts: { isDirectory: true },
scripts: { isDirectory: true },
tests: { isDirectory: true },
'README.txt': { isDirectory: false }
'README.txt': { isDirectory: false },
'.prettierrc.json': { isDirectory: false },
}, null, '/')
},
'Should throw error on current file #group7': async function (browser: NightwatchBrowser) {
@ -294,7 +295,8 @@ module.exports = {
contracts: { isDirectory: true },
scripts: { isDirectory: true },
tests: { isDirectory: true },
'README.txt': { isDirectory: false }
'README.txt': { isDirectory: false },
'.prettierrc.json': { isDirectory: false }
}, null, '/')
},
'Should get all workspaces #group2': async function (browser: NightwatchBrowser) {
@ -321,14 +323,14 @@ module.exports = {
// DGIT
'Should have changes on new workspace #group3': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'filePanel:createWorkspace', null, null, 'dgit')
await clickAndCheckLog(browser, 'dGitProvider:status', [["README.txt",0,2,0],["contracts/1_Storage.sol",0,2,0],["contracts/2_Owner.sol",0,2,0],["contracts/3_Ballot.sol",0,2,0],["scripts/deploy_with_ethers.ts",0,2,0],["scripts/deploy_with_web3.ts",0,2,0],["scripts/ethers-lib.ts",0,2,0],["scripts/web3-lib.ts",0,2,0],["tests/Ballot_test.sol",0,2,0],["tests/storage.test.js",0,2,0]], null, null)
await clickAndCheckLog(browser, 'dGitProvider:status', [[".prettierrc.json",0,2,0], ["README.txt",0,2,0],["contracts/1_Storage.sol",0,2,0],["contracts/2_Owner.sol",0,2,0],["contracts/3_Ballot.sol",0,2,0],["scripts/deploy_with_ethers.ts",0,2,0],["scripts/deploy_with_web3.ts",0,2,0],["scripts/ethers-lib.ts",0,2,0],["scripts/web3-lib.ts",0,2,0],["tests/Ballot_test.sol",0,2,0],["tests/storage.test.js",0,2,0]], null, null)
},
'Should stage contract #group3': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'dGitProvider:add', null, null, {
filepath: 'contracts/1_Storage.sol'
})
await clickAndCheckLog(browser, 'dGitProvider:status', [["README.txt",0,2,0],["contracts/1_Storage.sol",0,2,2],["contracts/2_Owner.sol",0,2,0],["contracts/3_Ballot.sol",0,2,0],["scripts/deploy_with_ethers.ts",0,2,0],["scripts/deploy_with_web3.ts",0,2,0],["scripts/ethers-lib.ts",0,2,0],["scripts/web3-lib.ts",0,2,0],["tests/Ballot_test.sol",0,2,0],["tests/storage.test.js",0,2,0]], null, null)
await clickAndCheckLog(browser, 'dGitProvider:status', [[".prettierrc.json",0,2,0],["README.txt",0,2,0],["contracts/1_Storage.sol",0,2,2],["contracts/2_Owner.sol",0,2,0],["contracts/3_Ballot.sol",0,2,0],["scripts/deploy_with_ethers.ts",0,2,0],["scripts/deploy_with_web3.ts",0,2,0],["scripts/ethers-lib.ts",0,2,0],["scripts/web3-lib.ts",0,2,0],["tests/Ballot_test.sol",0,2,0],["tests/storage.test.js",0,2,0]], null, null)
},
'Should commit changes #group3': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'dGitProvider:commit', null, null, { author: { name: 'Remix', email: 'Remix' }, message: 'commit-message' })

@ -122,7 +122,7 @@ module.exports = {
const fileList = document.querySelector('*[data-id="treeViewUltreeViewMenu"]')
return fileList.getElementsByTagName('li').length;
}, [], function (result) {
browser.assert.equal(result.value, 0, 'Incorrect number of files');
browser.assert.equal(result.value, 1, 'Incorrect number of files');
});
},

@ -6,7 +6,11 @@ import sol from './code-format/index'
import * as ts from 'prettier/parser-typescript'
import * as babel from 'prettier/parser-babel'
import * as espree from 'prettier/parser-espree'
import * as yml from 'prettier/parser-yaml'
import path from 'path'
import yaml from 'js-yaml'
import toml from 'toml'
import { filePathFilter, AnyFilter } from '@jsdevtools/file-path-filter'
const profile = {
name: 'codeFormatter',
@ -16,6 +20,51 @@ const profile = {
version: '0.0.1'
}
const defaultOptions = {
"overrides": [
{
"files": "*.sol",
"options": {
"printWidth": 80,
"tabWidth": 4,
"useTabs": false,
"singleQuote": false,
"bracketSpacing": false,
}
},
{
"files": "*.yml",
"options": {
}
},
{
"files": "*.yaml",
"options": {
}
},
{
"files": "*.toml",
"options": {
}
},
{
"files": "*.json",
"options": {
}
},
{
"files": "*.js",
"options": {
}
},
{
"files": "*.ts",
"options": {
}
}
]
}
export class CodeFormat extends Plugin {
constructor() {
@ -57,9 +106,142 @@ export class CodeFormat extends Plugin {
case '.json':
parserName = 'json'
break
case '.yml':
parserName = 'yaml'
break
case '.yaml':
parserName = 'yaml'
break
}
if (file === '.prettierrc') {
parserName = 'json'
}
const possibleFileNames = [
'.prettierrc',
'.prettierrc.json',
'.prettierrc.yaml',
'.prettierrc.yml',
'.prettierrc.toml',
'.prettierrc.js',
'.prettierrc.cjs',
'prettier.config.js',
'prettier.config.cjs',
'.prettierrc.json5',
]
const prettierConfigFile = await findAsync(possibleFileNames, async (fileName) => {
const exists = await this.call('fileManager', 'exists', fileName)
return exists
})
let parsed = null
if (prettierConfigFile) {
let prettierConfig = await this.call('fileManager', 'readFile', prettierConfigFile)
if (prettierConfig) {
if (prettierConfigFile.endsWith('.yaml') || prettierConfigFile.endsWith('.yml')) {
try {
parsed = yaml.load(prettierConfig)
} catch (e) {
// do nothing
}
} else if (prettierConfigFile.endsWith('.toml')) {
try {
parsed = toml.parse(prettierConfig)
} catch (e) {
// do nothing
}
} else if (prettierConfigFile.endsWith('.json') || prettierConfigFile.endsWith('.json5')) {
try {
parsed = JSON.parse(prettierConfig)
} catch (e) {
// do nothing
}
} else if (prettierConfigFile === '.prettierrc') {
try {
parsed = JSON.parse(prettierConfig)
} catch (e) {
// do nothing
}
if (!parsed) {
try {
parsed = yaml.load(prettierConfig)
} catch (e) {
// do nothing
}
}
} else if (prettierConfigFile.endsWith('.js') || prettierConfigFile.endsWith('.cjs')) {
// remove any comments
prettierConfig = prettierConfig.replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '')
// add quotes to keys
prettierConfig = prettierConfig.replace(/([a-zA-Z0-9_]+)(\s*):/g, '"$1"$2:')
// remove comma from last key
prettierConfig = prettierConfig.replace(/,(\s*})/g, '$1')
// remove any semi-colons
prettierConfig = prettierConfig.replace(/;/g, '')
// convert single quotes to double quotes
prettierConfig = prettierConfig.replace(/'/g, '"')
try {
parsed = JSON.parse(prettierConfig.replace('module.exports = ', '').replace('module.exports=', ''))
} catch (e) {
// do nothing
}
}
}
} else {
parsed = defaultOptions
await this.call('fileManager', 'writeFile', '.prettierrc.json', JSON.stringify(parsed, null, 2))
}
if (!parsed && prettierConfigFile) {
this.call('notification', 'toast', `Error parsing prettier config file: ${prettierConfigFile}`)
}
// merge options
if (parsed) {
options = {
...options,
...parsed,
}
}
// search for overrides
if (parsed && parsed.overrides) {
const override = parsed.overrides.find((override) => {
if (override.files) {
const pathFilter: AnyFilter = {}
pathFilter.include = setGlobalExpression(override.files)
const filteredFiles = [file]
.filter(filePathFilter(pathFilter))
if (filteredFiles.length) {
return true
}
}
})
const validParsers = ['typescript', 'babel', 'espree', 'solidity-parse', 'json', 'yaml', 'solidity-parse']
if (override && override.options && override.options.parser) {
if (validParsers.includes(override.options.parser)) {
parserName = override.options.parser
} else {
this.call('notification', 'toast', `Invalid parser: ${override.options.parser}! Valid options are ${validParsers.join(', ')}`)
}
delete override.options.parser
}
if (override) {
options = {
...options,
...override.options,
}
}
}
const result = prettier.format(content, {
plugins: [sol as any, ts, babel, espree],
plugins: [sol as any, ts, babel, espree, yml],
parser: parserName,
...options
})
@ -71,12 +253,22 @@ export class CodeFormat extends Plugin {
}
function getRange(index, node) {
if (node.range) {
return node.range[index];
}
if (node.expression && node.expression.range) {
return node.expression.range[index];
}
return null;
//*.sol, **/*.txt, contracts/*
const setGlobalExpression = (paths: string) => {
const results = []
paths.split(',').forEach(path => {
path = path.trim()
if (path.startsWith('*.')) path = path.replace(/(\*\.)/g, '**/*.')
if (path.endsWith('/*') && !path.endsWith('/**/*'))
path = path.replace(/(\*)/g, '**/*.*')
results.push(path)
})
return results
}
async function findAsync(arr, asyncCallback) {
const promises = arr.map(asyncCallback);
const results = await Promise.all(promises);
const index = results.findIndex(result => result);
return arr[index];
}

@ -0,0 +1,44 @@
{
"overrides": [
{
"files": "*.sol",
"options": {
"printWidth": 80,
"tabWidth": 4,
"useTabs": false,
"singleQuote": false,
"bracketSpacing": false
}
},
{
"files": "*.yml",
"options": {
}
},
{
"files": "*.yaml",
"options": {
}
},
{
"files": "*.toml",
"options": {
}
},
{
"files": "*.json",
"options": {
}
},
{
"files": "*.js",
"options": {
}
},
{
"files": "*.ts",
"options": {
}
}
]
}

@ -1 +1,6 @@
export default async () => { return {}}
export default async () => {
return {
// @ts-ignore
'.prettierrc.json': (await import('raw-loader!./.prettierrc')).default
}
}

@ -0,0 +1,44 @@
{
"overrides": [
{
"files": "*.sol",
"options": {
"printWidth": 80,
"tabWidth": 4,
"useTabs": false,
"singleQuote": false,
"bracketSpacing": false
}
},
{
"files": "*.yml",
"options": {
}
},
{
"files": "*.yaml",
"options": {
}
},
{
"files": "*.toml",
"options": {
}
},
{
"files": "*.json",
"options": {
}
},
{
"files": "*.js",
"options": {
}
},
{
"files": "*.ts",
"options": {
}
}
]
}

@ -9,6 +9,8 @@ export default async () => {
// @ts-ignore
'scripts/ethers-lib.ts': (await import('!!raw-loader!./scripts/ethers-lib.ts')).default,
// @ts-ignore
'scripts/web3-lib.ts': (await import('!!raw-loader!./scripts/web3-lib.ts')).default
'scripts/web3-lib.ts': (await import('!!raw-loader!./scripts/web3-lib.ts')).default,
// @ts-ignore
'.prettierrc.json': (await import('raw-loader!./.prettierrc')).default
}
}

@ -0,0 +1,44 @@
{
"overrides": [
{
"files": "*.sol",
"options": {
"printWidth": 80,
"tabWidth": 4,
"useTabs": false,
"singleQuote": false,
"bracketSpacing": false
}
},
{
"files": "*.yml",
"options": {
}
},
{
"files": "*.yaml",
"options": {
}
},
{
"files": "*.toml",
"options": {
}
},
{
"files": "*.json",
"options": {
}
},
{
"files": "*.js",
"options": {
}
},
{
"files": "*.ts",
"options": {
}
}
]
}

@ -8,7 +8,7 @@ export default async (opts) => {
}
const filesObj = {
'contracts/MyToken.sol': erc1155.print({ ...erc1155.defaults, upgradeable: opts && opts.upgradeable ? opts.upgradeable : false}),
'contracts/MyToken.sol': erc1155.print({ ...erc1155.defaults, upgradeable: opts && opts.upgradeable ? opts.upgradeable : false }),
// @ts-ignore
'scripts/deploy_with_ethers.ts': (await import('!!raw-loader!./scripts/deploy_with_ethers.ts')).default,
// @ts-ignore
@ -16,7 +16,9 @@ export default async (opts) => {
// @ts-ignore
'scripts/ethers-lib.ts': (await import('!!raw-loader!./scripts/ethers-lib.ts')).default,
// @ts-ignore
'scripts/web3-lib.ts': (await import('!!raw-loader!./scripts/web3-lib.ts')).default
'scripts/web3-lib.ts': (await import('!!raw-loader!./scripts/web3-lib.ts')).default,
// @ts-ignore
'.prettierrc.json': (await import('raw-loader!./.prettierrc')).default
}
// If no options is selected, opts.upgradeable will be undefined
// We do not show test file for upgradeable contract

@ -0,0 +1,44 @@
{
"overrides": [
{
"files": "*.sol",
"options": {
"printWidth": 80,
"tabWidth": 4,
"useTabs": false,
"singleQuote": false,
"bracketSpacing": false
}
},
{
"files": "*.yml",
"options": {
}
},
{
"files": "*.yaml",
"options": {
}
},
{
"files": "*.toml",
"options": {
}
},
{
"files": "*.json",
"options": {
}
},
{
"files": "*.js",
"options": {
}
},
{
"files": "*.ts",
"options": {
}
}
]
}

@ -6,7 +6,7 @@ export default async (opts) => {
erc20.defaults.burnable = opts.burnable
erc20.defaults.pausable = opts.pausable
}
const filesObj = {
'contracts/MyToken.sol': erc20.print({ ...erc20.defaults, upgradeable: opts && opts.upgradeable ? opts.upgradeable : false }),
// @ts-ignore
@ -16,7 +16,9 @@ export default async (opts) => {
// @ts-ignore
'scripts/ethers-lib.ts': (await import('!!raw-loader!./scripts/ethers-lib.ts')).default,
// @ts-ignore
'scripts/web3-lib.ts': (await import('!!raw-loader!./scripts/web3-lib.ts')).default
'scripts/web3-lib.ts': (await import('!!raw-loader!./scripts/web3-lib.ts')).default,
// @ts-ignore
'.prettierrc.json': (await import('raw-loader!./.prettierrc')).default
}
// If no options is selected, opts.upgradeable will be undefined

@ -0,0 +1,44 @@
{
"overrides": [
{
"files": "*.sol",
"options": {
"printWidth": 80,
"tabWidth": 4,
"useTabs": false,
"singleQuote": false,
"bracketSpacing": false
}
},
{
"files": "*.yml",
"options": {
}
},
{
"files": "*.yaml",
"options": {
}
},
{
"files": "*.toml",
"options": {
}
},
{
"files": "*.json",
"options": {
}
},
{
"files": "*.js",
"options": {
}
},
{
"files": "*.ts",
"options": {
}
}
]
}

@ -16,7 +16,9 @@ export default async (opts) => {
// @ts-ignore
'scripts/ethers-lib.ts': (await import('!!raw-loader!./scripts/ethers-lib.ts')).default,
// @ts-ignore
'scripts/web3-lib.ts': (await import('!!raw-loader!./scripts/web3-lib.ts')).default
'scripts/web3-lib.ts': (await import('!!raw-loader!./scripts/web3-lib.ts')).default,
// @ts-ignore
'.prettierrc.json': (await import('raw-loader!./.prettierrc')).default
}
// If no options is selected, opts.upgradeable will be undefined

@ -0,0 +1,44 @@
{
"overrides": [
{
"files": "*.sol",
"options": {
"printWidth": 80,
"tabWidth": 4,
"useTabs": false,
"singleQuote": false,
"bracketSpacing": false
}
},
{
"files": "*.yml",
"options": {
}
},
{
"files": "*.yaml",
"options": {
}
},
{
"files": "*.toml",
"options": {
}
},
{
"files": "*.json",
"options": {
}
},
{
"files": "*.js",
"options": {
}
},
{
"files": "*.ts",
"options": {
}
}
]
}

@ -20,5 +20,7 @@ export default async () => {
'tests/storage.test.js': (await import('!!raw-loader!./tests/storage.test.js')).default,
// @ts-ignore
'README.txt': (await import('raw-loader!./README.txt')).default,
// @ts-ignore
'.prettierrc.json': (await import('raw-loader!./.prettierrc')).default,
}
}

@ -0,0 +1,44 @@
{
"overrides": [
{
"files": "*.sol",
"options": {
"printWidth": 80,
"tabWidth": 4,
"useTabs": false,
"singleQuote": false,
"bracketSpacing": false
}
},
{
"files": "*.yml",
"options": {
}
},
{
"files": "*.yaml",
"options": {
}
},
{
"files": "*.toml",
"options": {
}
},
{
"files": "*.json",
"options": {
}
},
{
"files": "*.js",
"options": {
}
},
{
"files": "*.ts",
"options": {
}
}
]
}

@ -11,6 +11,10 @@ export default async () => {
// @ts-ignore
'scripts/web3-lib.ts': (await import('!!raw-loader!./scripts/web3-lib.ts')).default,
// @ts-ignore
'tests/SampleERC20_test.sol': (await import('raw-loader!./tests/SampleERC20_test.sol')).default
'tests/SampleERC20_test.sol': (await import('raw-loader!./tests/SampleERC20_test.sol')).default,
// @ts-ignore
'.prettierrc.json': (await import('raw-loader!./.prettierrc')).default,
// @ts-ignore
'.prettierrc2.json': (await import('raw-loader!./.prettierrc')).default
}
}

@ -194,6 +194,7 @@
"isbinaryfile": "^3.0.2",
"isomorphic-git": "^1.8.2",
"jquery": "^3.3.1",
"js-yaml": "^4.1.0",
"jszip": "^3.6.0",
"latest-version": "^5.1.0",
"merge": "^2.1.1",
@ -219,6 +220,7 @@
"string-similarity": "^4.0.4",
"swarmgw": "^0.3.1",
"time-stamp": "^2.2.0",
"toml": "^3.0.0",
"tree-kill": "^1.2.2",
"ts-loader": "^9.2.6",
"tslib": "^2.3.0",

@ -1452,6 +1452,11 @@
"glob": "*.md",
"input": "libs/remix-ws-templates/",
"output": "/"
},
{
"glob": "templates/**/.prettierrc",
"input": "libs/remix-ws-templates/src/",
"output": "src/"
}
]
}

@ -14765,7 +14765,7 @@ js-yaml@4.0.0:
dependencies:
argparse "^2.0.1"
js-yaml@4.1.0:
js-yaml@4.1.0, js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
@ -22865,6 +22865,11 @@ toidentifier@1.0.0:
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
toml@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee"
integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==
touch@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b"

Loading…
Cancel
Save