mirror of
https://github.com/cypress-io/cypress.git
synced 2026-02-11 09:40:11 -06:00
fix: Properly handle formatting and escaping markdown for commands and assertions in Command Log (#28583)
* bump markdown-it * Update code to wrap assertions back in strong html * Update the logic to be more broad in not applying markdown formmated for any assertions * Add code covering complex assertions * Add code/cases to handle html elements in assertions * Fix studio tests - these should be 'expected' * fix the regex and clean up code * Add condition for 'not to' since the terminology is switched on match * add changelog entry * fix date format in changelog * remove space * Fix bug with studio displaying generated assertions incorrectly * revert studio changes to track in a different PR * remove old 'type' arg that was passed for formattedMessage before * Update code to not format markdown for commands that accept URLs * changelog update
This commit is contained in:
@@ -6,6 +6,7 @@ _Released 1/2/2024 (PENDING)_
|
||||
**Bugfixes:**
|
||||
|
||||
- Now 'node_modules' will not be ignored if a project path or a provided path to spec files contains it. Fixes [#23616](https://github.com/cypress-io/cypress/issues/23616).
|
||||
- Updated display of assertions and commands with a URL argument to escape markdown formatting so that values are displayed as is and assertion values display as bold. Fixes [#24960](https://github.com/cypress-io/cypress/issues/24960) and [#28100](https://github.com/cypress-io/cypress/issues/28100).
|
||||
- When generating assertions via Cypress Studio, the preview of the generated assertions now correctly displays the past tense of 'expected' instead of 'expect'. Fixed in [#28593](https://github.com/cypress-io/cypress/pull/28593).
|
||||
|
||||
**Dependency Updates:**
|
||||
|
||||
@@ -91,7 +91,6 @@ it('visits a basic html page', () => {
|
||||
})
|
||||
|
||||
assertStudioHookCount(2)
|
||||
|
||||
cy.getAutIframe().within(() => {
|
||||
cy.get('#increment').rightclick().then(() => {
|
||||
cy.get('.__cypress-studio-assertions-menu').shadow().contains('be visible').realClick()
|
||||
|
||||
@@ -185,6 +185,56 @@ describe('commands', { viewportHeight: 1000 }, () => {
|
||||
cy.percySnapshot()
|
||||
})
|
||||
|
||||
it('displays assertions formatted', () => {
|
||||
addCommand(runner, {
|
||||
id: 1291,
|
||||
name: 'assert',
|
||||
type: 'child',
|
||||
message: 'expected **value** to equal **value**',
|
||||
state: 'passed',
|
||||
timeout: 4000,
|
||||
group: 1229,
|
||||
groupLevel: 2,
|
||||
wallClockStartedAt: inProgressStartedAt,
|
||||
})
|
||||
|
||||
addCommand(runner, {
|
||||
id: 1292,
|
||||
name: 'assert',
|
||||
type: 'child',
|
||||
message: 'expected **value** to match **value**',
|
||||
state: 'passed',
|
||||
timeout: 4000,
|
||||
group: 1229,
|
||||
groupLevel: 2,
|
||||
wallClockStartedAt: inProgressStartedAt,
|
||||
})
|
||||
|
||||
addCommand(runner, {
|
||||
id: 1293,
|
||||
name: 'assert',
|
||||
type: 'child',
|
||||
message: 'expected **_value_** to contain **_value_**',
|
||||
state: 'passed',
|
||||
timeout: 4000,
|
||||
group: 1229,
|
||||
groupLevel: 2,
|
||||
wallClockStartedAt: inProgressStartedAt,
|
||||
})
|
||||
|
||||
cy.contains('.command-message-text', 'to equal')
|
||||
.find('strong').should('have.length', 2)
|
||||
.and('contain', 'value')
|
||||
.and('not.contain', '*')
|
||||
|
||||
cy.contains('.command-message-text', 'to match')
|
||||
.find('strong').should('have.length', 2)
|
||||
.and('contain', 'value')
|
||||
.and('not.contain', '*')
|
||||
|
||||
cy.percySnapshot()
|
||||
})
|
||||
|
||||
it('includes the type class', () => {
|
||||
cy.contains('#exists').closest('.command-wrapper')
|
||||
.should('have.class', 'command-type-parent')
|
||||
|
||||
@@ -7,31 +7,115 @@ describe('formattedMessage', () => {
|
||||
expect(result).to.equal('')
|
||||
})
|
||||
|
||||
it('maintains special characters when using "to match"', () => {
|
||||
const specialMessage = 'expected **__*abcdef*__** to match /__.*abcdef.*__/'
|
||||
const result = formattedMessage(specialMessage)
|
||||
describe('when assertion', () => {
|
||||
it('does not display extraneous "*" for to equal assertions', () => {
|
||||
const specialMessage = 'expected **abcdef** to equal **abcdef**'
|
||||
const result = formattedMessage(specialMessage, 'assert')
|
||||
|
||||
expect(result).to.equal('expected <strong><strong><em>abcdef</em></strong></strong> to match <strong>/__.*abcdef.*__/</strong>')
|
||||
expect(result).to.equal('expected <strong>abcdef</strong> to equal <strong>abcdef</strong>')
|
||||
})
|
||||
|
||||
it('does not display extraneous "*" for to not equal assertions', () => {
|
||||
const specialMessage = 'expected **abcdef** to not equal **abcde**'
|
||||
const result = formattedMessage(specialMessage, 'assert')
|
||||
|
||||
expect(result).to.equal('expected <strong>abcdef</strong> to not equal <strong>abcde</strong>')
|
||||
})
|
||||
|
||||
it('maintains special characters when using "to match"', () => {
|
||||
const specialMessage = 'expected **__*abcdef*__** to match **/__.*abcdef.*__/**'
|
||||
const result = formattedMessage(specialMessage, 'assert')
|
||||
|
||||
expect(result).to.equal('expected <strong>__*abcdef*__</strong> to match <strong>/__.*abcdef.*__/</strong>')
|
||||
})
|
||||
|
||||
it('maintains special characters when using "to not match"', () => {
|
||||
const specialMessage = 'expected **__*abcdef*__** not to match **/__.*abcde.*__/**'
|
||||
const result = formattedMessage(specialMessage, 'assert')
|
||||
|
||||
expect(result).to.equal('expected <strong>__*abcdef*__</strong> not to match <strong>/__.*abcde.*__/</strong>')
|
||||
})
|
||||
|
||||
it('maintains special characters when using "to equal"', () => {
|
||||
const specialMessage = 'expected *****abcdef***** to equal *****abcdef*****'
|
||||
const result = formattedMessage(specialMessage, 'assert')
|
||||
|
||||
expect(result).to.equal('expected <strong>***abcdef***</strong> to equal <strong>***abcdef***</strong>')
|
||||
})
|
||||
|
||||
it('maintains special characters when using "to not equal"', () => {
|
||||
const specialMessage = 'expected *****abcdef***** to not equal *****abcde*****'
|
||||
const result = formattedMessage(specialMessage, 'assert')
|
||||
|
||||
expect(result).to.equal('expected <strong>***abcdef***</strong> to not equal <strong>***abcde***</strong>')
|
||||
})
|
||||
|
||||
it('maintains initial spaces on new lines', () => {
|
||||
const specialMessage = 'expected **hello\n world `code block`** to equal **hello\n world `code block`**'
|
||||
const result = formattedMessage(specialMessage, 'assert')
|
||||
|
||||
expect(result).to.equal('expected <strong>hello\n world `code block`</strong> to equal <strong>hello\n world `code block`</strong>')
|
||||
})
|
||||
|
||||
it('bolds asterisks using "to contain"', () => {
|
||||
const specialMessage = 'expected **glob*glob** to contain *****'
|
||||
const result = formattedMessage(specialMessage, 'assert')
|
||||
|
||||
expect(result).to.equal('expected <strong>glob*glob</strong> to contain <strong>*</strong>')
|
||||
})
|
||||
|
||||
it('bolds asterisks with complex assertions', () => {
|
||||
const specialMessage = 'expected **span** to have CSS property **background-color** with the value **rgb(0, 0, 0)**, but the value was **rgba(0, 0, 0, 0)**'
|
||||
const result = formattedMessage(specialMessage)
|
||||
|
||||
expect(result).to.equal('expected <strong>span</strong> to have CSS property <strong>background-color</strong> with the value <strong>rgb(0, 0, 0)</strong>, but the value was <strong>rgba(0, 0, 0, 0)</strong>')
|
||||
})
|
||||
|
||||
it('bolds asterisks with simple assertions', () => {
|
||||
const specialMessage = 'expected **dom** to be visible'
|
||||
const result = formattedMessage(specialMessage, 'assert')
|
||||
|
||||
expect(result).to.equal('expected <strong>dom</strong> to be visible')
|
||||
})
|
||||
|
||||
it('bolds assertions and displays html correctly', () => {
|
||||
// expected <button#increment> to be enabled
|
||||
const specialMessage = 'expected **<button#increment>** to be enabled'
|
||||
const result = formattedMessage(specialMessage, 'assert')
|
||||
|
||||
expect(result).to.equal('expected <strong><button#increment></strong> to be enabled')
|
||||
})
|
||||
})
|
||||
|
||||
it('maintains special characters when using "to contain"', () => {
|
||||
const specialMessage = 'expected ***abcdef*** to equal ***abcdef***'
|
||||
const result = formattedMessage(specialMessage)
|
||||
describe('when command that accepts url', () => {
|
||||
it('cy.visit does not do markdown formatting', () => {
|
||||
const specialMessage = 'http://www.test.com/__Path__99~~path~~'
|
||||
const result = formattedMessage(specialMessage, 'visit')
|
||||
|
||||
expect(result).to.equal('expected <em><strong>abcdef</strong></em> to equal <strong>***abcdef***</strong>')
|
||||
expect(result).to.equal('http://www.test.com/__Path__99~~path~~')
|
||||
})
|
||||
|
||||
it('cy.request does not do markdown formatting', () => {
|
||||
const specialMessage = 'http://www.test.com/__Path__99~~path~~'
|
||||
const result = formattedMessage(specialMessage, 'request')
|
||||
|
||||
expect(result).to.equal('http://www.test.com/__Path__99~~path~~')
|
||||
})
|
||||
|
||||
it('cy.origin does not do markdown formatting', () => {
|
||||
const specialMessage = 'http://www.test.com/__Path__99~~path~~'
|
||||
const result = formattedMessage(specialMessage, 'origin')
|
||||
|
||||
expect(result).to.equal('http://www.test.com/__Path__99~~path~~')
|
||||
})
|
||||
})
|
||||
|
||||
it('does NOT maintain special characters when "to equal" or "to match" are not in assertion', () => {
|
||||
const specialMessage = 'expected ***abcdef*** to contain ***abcdef***'
|
||||
const result = formattedMessage(specialMessage)
|
||||
describe('when not an assertion', () => {
|
||||
it('displays special characters as markdown when not assertion', () => {
|
||||
const specialMessage = 'message\n here `code block` with *formatting*'
|
||||
const result = formattedMessage(specialMessage)
|
||||
|
||||
expect(result).to.equal('expected <em><strong>abcdef</strong></em> to contain <em><strong>abcdef</strong></em>')
|
||||
})
|
||||
|
||||
it('maintains initial spaces on new lines', () => {
|
||||
const specialMessage = 'hello\n world `code block`'
|
||||
const result = formattedMessage(specialMessage)
|
||||
|
||||
expect(result).to.equal('hello<br>\n world <code>code block</code>')
|
||||
expect(result).to.equal(`message\nhere <code>code block</code> with <em>formatting</em>`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"cypress-multi-reporters": "1.4.0",
|
||||
"cypress-real-events": "1.6.0",
|
||||
"lodash": "^4.17.21",
|
||||
"markdown-it": "11.0.1",
|
||||
"markdown-it": "^14.0.0",
|
||||
"mobx": "5.15.4",
|
||||
"mobx-react": "6.1.8",
|
||||
"prismjs": "1.21.0",
|
||||
|
||||
@@ -27,23 +27,54 @@ import RunningIcon from '@packages/frontend-shared/src/assets/icons/status-runni
|
||||
const displayName = (model: CommandModel) => model.displayName || model.name
|
||||
const nameClassName = (name: string) => name.replace(/(\s+)/g, '-')
|
||||
|
||||
const mdBreaks = new Markdown({ breaks: true })
|
||||
const md = new Markdown()
|
||||
const mdOnlyHTML = new Markdown('zero').enable(['html_inline', 'html_block'])
|
||||
|
||||
export const formattedMessage = (message: string, type: string) => {
|
||||
const asterisksRegex = /^\*\*(.+?)\*\*$/gs
|
||||
// regex to match everything outside of expected/actual values like:
|
||||
// 'expected **<span>** to exist in the DOM'
|
||||
// `expected **glob*glob** to contain *****`
|
||||
// `expected **<span>** to have CSS property **background-color** with the value **rgb(0, 0, 0)**, but the value was **rgba(0, 0, 0, 0)**`
|
||||
const assertionRegex = /expected | to[^\*]+| not[^\*]+| with[^\*]+|, but[^\*]+/g
|
||||
|
||||
// used to format the display of command messages and error messages
|
||||
// we use markdown syntax within our error messages (code ticks, urls, etc)
|
||||
// and cy.log and Cypress.log supports markdown formatting
|
||||
export const formattedMessage = (message: string, name?: string) => {
|
||||
if (!message) return ''
|
||||
|
||||
const searchText = ['to match', 'to equal']
|
||||
const regex = new RegExp(searchText.join('|'))
|
||||
const split = message.split(regex)
|
||||
const matchingText = searchText.find((text) => message.includes(text))
|
||||
const textToConvert = [split[0].trim(), ...(matchingText ? [matchingText] : [])].join(' ')
|
||||
const spaceEscapedText = textToConvert.replace(/^ +/gm, (initialSpaces) => ' '.repeat(initialSpaces.length)) //   is the HTML entity for a space
|
||||
// we don't want <br> in our error messages, but allow it in Cypress.log
|
||||
const converted = type === 'error' ? md.renderInline(spaceEscapedText) : mdBreaks.renderInline(spaceEscapedText)
|
||||
const assertion = (split[1] && [`<strong>${split[1].trim()}</strong>`]) || []
|
||||
// the command message is formatted as 'expected <actual> to {assertion} <expected>'
|
||||
const assertionArray = message.match(assertionRegex)
|
||||
|
||||
return [converted, ...assertion].join(' ')
|
||||
const expectedActualArray = () => {
|
||||
// get the expected and actual values of assertions
|
||||
const splitTrim = message.split(assertionRegex).filter(Boolean).map((s) => s.trim())
|
||||
|
||||
// replace outside double asterisks with strong tags
|
||||
return splitTrim.map((s) => {
|
||||
// we want to escape HTML chars so that they display
|
||||
// correctly in the command log: <p> -> <p>
|
||||
const HTMLEscapedString = mdOnlyHTML.renderInline(s)
|
||||
|
||||
return HTMLEscapedString.replace(asterisksRegex, `<strong>$1</strong>`)
|
||||
})
|
||||
}
|
||||
|
||||
if (name === 'assert' && assertionArray) {
|
||||
// for assertions print the exact text so that characters like _ and *
|
||||
// are not escaped in the assertion display when comparing values
|
||||
const result = assertionArray.flatMap((s, index) => [s, expectedActualArray()[index]])
|
||||
|
||||
return result.join('')
|
||||
}
|
||||
|
||||
// if the command has url args, don't format those chars like __ and ~~
|
||||
if (name === 'visit' || name === 'request' || name === 'origin') {
|
||||
return message
|
||||
}
|
||||
|
||||
// format markdown for everything else
|
||||
return md.renderInline(message)
|
||||
}
|
||||
|
||||
const invisibleMessage = (model: CommandModel) => {
|
||||
@@ -228,7 +259,7 @@ const Message = observer(({ model }: MessageProps) => (
|
||||
)}
|
||||
{!!model.displayMessage && <span
|
||||
className='command-message-text'
|
||||
dangerouslySetInnerHTML={{ __html: formattedMessage(model.displayMessage) }}
|
||||
dangerouslySetInnerHTML={{ __html: formattedMessage(model.displayMessage, model.name) }}
|
||||
/>}
|
||||
</span>
|
||||
))
|
||||
|
||||
@@ -90,7 +90,7 @@ const TestError = (props: TestErrorProps) => {
|
||||
{groupPlaceholder}
|
||||
<div className='runnable-err-content'>
|
||||
<div className='runnable-err-message'>
|
||||
<span dangerouslySetInnerHTML={{ __html: formattedMessage(err.message, 'error') }} />
|
||||
<span dangerouslySetInnerHTML={{ __html: formattedMessage(err.message) }} />
|
||||
<DocsUrl url={err.docsUrl} />
|
||||
</div>
|
||||
{codeFrame && <ErrorCodeFrame codeFrame={codeFrame} />}
|
||||
|
||||
57
yarn.lock
57
yarn.lock
@@ -13490,11 +13490,6 @@ entities@^4.2.0, entities@^4.4.0:
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
|
||||
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
|
||||
|
||||
entities@~2.0.0:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f"
|
||||
integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==
|
||||
|
||||
entities@~3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4"
|
||||
@@ -19366,13 +19361,6 @@ lines-and-columns@~2.0.3:
|
||||
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-2.0.3.tgz#b2f0badedb556b747020ab8ea7f0373e22efac1b"
|
||||
integrity sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==
|
||||
|
||||
linkify-it@^3.0.1:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.2.tgz#f55eeb8bc1d3ae754049e124ab3bb56d97797fb8"
|
||||
integrity sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ==
|
||||
dependencies:
|
||||
uc.micro "^1.0.1"
|
||||
|
||||
linkify-it@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-4.0.1.tgz#01f1d5e508190d06669982ba31a7d9f56a5751ec"
|
||||
@@ -19380,6 +19368,13 @@ linkify-it@^4.0.1:
|
||||
dependencies:
|
||||
uc.micro "^1.0.1"
|
||||
|
||||
linkify-it@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-5.0.0.tgz#9ef238bfa6dc70bd8e7f9572b52d369af569b421"
|
||||
integrity sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==
|
||||
dependencies:
|
||||
uc.micro "^2.0.0"
|
||||
|
||||
lint-staged@11.1.2:
|
||||
version "11.1.2"
|
||||
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-11.1.2.tgz#4dd78782ae43ee6ebf2969cad9af67a46b33cd90"
|
||||
@@ -20166,17 +20161,6 @@ map-visit@^1.0.0:
|
||||
promise "7.0.4"
|
||||
socket-retry-connect "0.0.1"
|
||||
|
||||
markdown-it@11.0.1:
|
||||
version "11.0.1"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-11.0.1.tgz#b54f15ec2a2193efa66dda1eb4173baea08993d6"
|
||||
integrity sha512-aU1TzmBKcWNNYvH9pjq6u92BML+Hz3h5S/QpfTFwiQF852pLT+9qHsrhM9JYipkOXZxGn+sGH8oyJE9FD9WezQ==
|
||||
dependencies:
|
||||
argparse "^1.0.7"
|
||||
entities "~2.0.0"
|
||||
linkify-it "^3.0.1"
|
||||
mdurl "^1.0.1"
|
||||
uc.micro "^1.0.5"
|
||||
|
||||
markdown-it@13.0.1:
|
||||
version "13.0.1"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-13.0.1.tgz#c6ecc431cacf1a5da531423fc6a42807814af430"
|
||||
@@ -20188,6 +20172,18 @@ markdown-it@13.0.1:
|
||||
mdurl "^1.0.1"
|
||||
uc.micro "^1.0.5"
|
||||
|
||||
markdown-it@^14.0.0:
|
||||
version "14.0.0"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.0.0.tgz#b4b2ddeb0f925e88d981f84c183b59bac9e3741b"
|
||||
integrity sha512-seFjF0FIcPt4P9U39Bq1JYblX0KZCjDLFFQPHpL5AzHpqPEKtosxmdq/LTVZnjfH7tjt9BxStm+wXcDBNuYmzw==
|
||||
dependencies:
|
||||
argparse "^2.0.1"
|
||||
entities "^4.4.0"
|
||||
linkify-it "^5.0.0"
|
||||
mdurl "^2.0.0"
|
||||
punycode.js "^2.3.1"
|
||||
uc.micro "^2.0.0"
|
||||
|
||||
marked-terminal@^5.0.0:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-5.1.1.tgz#d2edc2991841d893ee943b44b40b2ee9518b4d9f"
|
||||
@@ -20263,6 +20259,11 @@ mdurl@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
|
||||
integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=
|
||||
|
||||
mdurl@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-2.0.0.tgz#80676ec0433025dd3e17ee983d0fe8de5a2237e0"
|
||||
integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==
|
||||
|
||||
media-typer@0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||
@@ -24337,6 +24338,11 @@ pumpify@1.5.1, pumpify@^1.3.3, pumpify@^1.3.5:
|
||||
inherits "^2.0.3"
|
||||
pump "^2.0.0"
|
||||
|
||||
punycode.js@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7"
|
||||
integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==
|
||||
|
||||
punycode@1.3.2:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
|
||||
@@ -28951,6 +28957,11 @@ uc.micro@^1.0.1, uc.micro@^1.0.5:
|
||||
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
|
||||
integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
|
||||
|
||||
uc.micro@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.0.0.tgz#84b3c335c12b1497fd9e80fcd3bfa7634c363ff1"
|
||||
integrity sha512-DffL94LsNOccVn4hyfRe5rdKa273swqeA5DJpMOeFmEn1wCDc7nAbbB0gXlgBCL7TNzeTv6G7XVWzan7iJtfig==
|
||||
|
||||
uglify-js@^2.6:
|
||||
version "2.8.29"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
|
||||
|
||||
Reference in New Issue
Block a user