Optimization of code block (#1445)

* duplicate css rule

* remove all codeLine

* Fix: #1446

* Fix #942 #1310

* Fix copy paste will add one more empty line in code block

* remove debug codes

* Fix update thematic break error

* fix: #1447

* Update octokit/rest and url-loader

* Fix: CI test error

* Fix comment issue1

* Fix: escape charachters in code block
This commit is contained in:
Ran Luo 2019-10-08 14:12:51 +08:00 committed by GitHub
parent 4a24ff0954
commit 5b8da2cdf4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 242 additions and 242 deletions

View File

@ -116,6 +116,7 @@ function greeting () {
font: 'simple3d', font: 'simple3d',
space: false space: false
}) })
} else console.log(chalk.yellow.bold('\n lets-build')) } else {
console.log() console.log(chalk.yellow.bold('\n lets-build'))
}
} }

View File

@ -6,7 +6,7 @@
- languageInput - languageInput
- codeLine - codeContent (used in code block)
- atxLine (can not contain soft line break and hard line break use in atx heading) - atxLine (can not contain soft line break and hard line break use in atx heading)
@ -14,7 +14,7 @@
- paragraphContent (defaultValue use in paragraph and setext heading) - paragraphContent (defaultValue use in paragraph and setext heading)
- lang - only when it's code line - lang - only when it's functionType is `codeContent`
- All prismjs support language or empty string - All prismjs support language or empty string

View File

@ -34,7 +34,7 @@
}, },
"dependencies": { "dependencies": {
"@hfelix/electron-localshortcut": "^3.1.1", "@hfelix/electron-localshortcut": "^3.1.1",
"@octokit/rest": "^16.30.1", "@octokit/rest": "^16.31.0",
"arg": "^4.1.1", "arg": "^4.1.1",
"axios": "^0.19.0", "axios": "^0.19.0",
"ced": "^1.0.0", "ced": "^1.0.0",
@ -155,7 +155,7 @@
"svgo": "^1.3.0", "svgo": "^1.3.0",
"svgo-loader": "^2.2.1", "svgo-loader": "^2.2.1",
"to-string-loader": "^1.1.5", "to-string-loader": "^1.1.5",
"url-loader": "^2.1.0", "url-loader": "^2.2.0",
"vue-html-loader": "^1.2.4", "vue-html-loader": "^1.2.4",
"vue-loader": "^15.7.1", "vue-loader": "^15.7.1",
"vue-style-loader": "^4.1.2", "vue-style-loader": "^4.1.2",

View File

@ -103,12 +103,12 @@ export const updateSelectionMenus = (applicationMenu, { start, end, affiliation
if ( if (
(/th|td/.test(start.type) && /th|td/.test(end.type)) || (/th|td/.test(start.type) && /th|td/.test(end.type)) ||
(start.type === 'span' && start.block.functionType === 'codeLine') || (start.type === 'span' && start.block.functionType === 'codeContent') ||
(end.type === 'span' && end.block.functionType === 'codeLine') (end.type === 'span' && end.block.functionType === 'codeContent')
) { ) {
setParagraphMenuItemStatus(applicationMenu, false) setParagraphMenuItemStatus(applicationMenu, false)
if (start.block.functionType === 'codeLine' || end.block.functionType === 'codeLine') { if (start.block.functionType === 'codeContent' || end.block.functionType === 'codeContent') {
setMultipleStatus(applicationMenu, ['codeFencesMenuItem'], true) setMultipleStatus(applicationMenu, ['codeFencesMenuItem'], true)
formatMenuItem.submenu.items.forEach(item => (item.enabled = false)) formatMenuItem.submenu.items.forEach(item => (item.enabled = false))
} }

View File

@ -39,7 +39,7 @@ div.ag-show-quick-insert-hint p.ag-paragraph.ag-active > span.ag-paragraph-conte
.ag-atx-line:empty::after, .ag-atx-line:empty::after,
.ag-thematic-break-line:empty::after, .ag-thematic-break-line:empty::after,
.ag-code-line:empty::after, .ag-code-content:empty::after,
.ag-paragraph-content:empty::after { .ag-paragraph-content:empty::after {
content: '\200B'; content: '\200B';
} }
@ -47,7 +47,7 @@ div.ag-show-quick-insert-hint p.ag-paragraph.ag-active > span.ag-paragraph-conte
.ag-atx-line, .ag-atx-line,
.ag-thematic-break-line, .ag-thematic-break-line,
.ag-paragraph-content, .ag-paragraph-content,
.ag-code-line { .ag-code-content {
display: block; display: block;
white-space: pre-wrap; white-space: pre-wrap;
word-break: break-word; word-break: break-word;
@ -76,6 +76,7 @@ div.ag-show-quick-insert-hint p.ag-paragraph.ag-active > span.ag-paragraph-conte
.ag-hard-line-break-space::after { .ag-hard-line-break-space::after {
content: '↩'; content: '↩';
opacity: .5; opacity: .5;
font-family: monospace;
} }
.ag-line-end { .ag-line-end {
@ -402,7 +403,6 @@ li.ag-task-list-item > input[type=checkbox]::before {
content: ''; content: '';
width: 18px; width: 18px;
height: 18px; height: 18px;
box-sizing: border-box;
display: inline-block; display: inline-block;
border: 2px solid var(--editorColor50); border: 2px solid var(--editorColor50);
border-radius: 50%; border-radius: 50%;
@ -477,7 +477,7 @@ pre.ag-front-matter {
margin: 1rem 0; margin: 1rem 0;
} }
pre.ag-front-matter span.ag-code-line:first-of-type:empty::after { pre.ag-front-matter span.ag-code-content:first-of-type:empty::after {
content: 'Input YAML Front Matter...'; content: 'Input YAML Front Matter...';
color: var(--editorColor10); color: var(--editorColor10);
} }
@ -487,7 +487,7 @@ pre[data-role$='code'] span.ag-language-input:empty::after {
color: var(--editorColor10); color: var(--editorColor10);
} }
pre.ag-multiple-math span.ag-code-line:first-of-type:empty::after { pre.ag-multiple-math span.ag-code-content:first-of-type:empty::after {
content: 'Input Mathematical Formula...'; content: 'Input Mathematical Formula...';
color: var(--editorColor10); color: var(--editorColor10);
} }
@ -673,7 +673,7 @@ span.ag-emoji-marked-text {
.ag-emoji-marked-text::before { .ag-emoji-marked-text::before {
position: absolute; position: absolute;
content: attr(data-emoji); content: attr(data-emoji);
color: var(--editorColor); color: #000000;
top: 0; top: 0;
left: -1.3em; left: -1.3em;
font-size: 1em; font-size: 1em;

View File

@ -70,9 +70,6 @@ export const CLASS_OR_ID = genUpper2LowerKeyHash([
'AG_BULLET_LIST', 'AG_BULLET_LIST',
'AG_BULLET_LIST_ITEM', 'AG_BULLET_LIST_ITEM',
'AG_CHECKBOX_CHECKED', 'AG_CHECKBOX_CHECKED',
'AG_CODE_LINE',
'AG_CODE_LINE_ADD',
'AG_CODE_LINE_MINUS',
'AG_CONTAINER_BLOCK', 'AG_CONTAINER_BLOCK',
'AG_CONTAINER_PREVIEW', 'AG_CONTAINER_PREVIEW',
'AG_CONTAINER_ICON', 'AG_CONTAINER_ICON',

View File

@ -308,7 +308,7 @@ const backspaceCtrl = ContentState => {
if ( if (
block.type === 'span' && block.type === 'span' &&
block.functionType === 'codeLine' && block.functionType === 'codeContent' &&
left === 0 && left === 0 &&
!block.preSibling !block.preSibling
) { ) {

View File

@ -136,7 +136,7 @@ const clickCtrl = ContentState => {
start.key === end.key && start.key === end.key &&
start.offset !== end.offset && start.offset !== end.offset &&
HAS_TEXT_BLOCK_REG.test(block.type) && HAS_TEXT_BLOCK_REG.test(block.type) &&
block.functionType !== 'codeLine' && block.functionType !== 'codeContent' &&
block.functionType !== 'languageInput' block.functionType !== 'languageInput'
) { ) {
const reference = this.getPositionReference() const reference = this.getPositionReference()

View File

@ -79,32 +79,41 @@ const codeBlockCtrl = ContentState => {
if (block.type === 'span') { if (block.type === 'span') {
block = this.getParent(block) block = this.getParent(block)
} }
// if it's not a p block, no need to update // If it's not a p block, no need to update
if (block.type !== 'p') return false if (block.type !== 'p') return false
// if p block's children are more than one, no need to update // If p block's children are more than one, no need to update
if (block.children.length !== 1) return false if (block.children.length !== 1) return false
const { text } = block.children[0] const { text } = block.children[0]
const match = CODE_UPDATE_REP.exec(text) const match = CODE_UPDATE_REP.exec(text)
if (match || lang) { if (match || lang) {
const codeBlock = this.createBlock('code')
const firstLine = this.createBlock('span', { text: code })
const language = lang || (match ? match[1] : '') const language = lang || (match ? match[1] : '')
const inputBlock = this.createBlock('span', { text: language }) const codeBlock = this.createBlock('code', {
lang: language
})
const codeContent = this.createBlock('span', {
text: code,
lang: language,
functionType: 'codeContent'
})
const inputBlock = this.createBlock('span', {
text: language,
functionType: 'languageInput'
})
loadLanguage(language) loadLanguage(language)
inputBlock.functionType = 'languageInput'
block.type = 'pre' block.type = 'pre'
block.functionType = 'fencecode' block.functionType = 'fencecode'
block.lang = language block.lang = language
block.text = '' block.text = ''
block.history = null block.history = null
block.children = [] block.children = []
codeBlock.lang = language
firstLine.lang = language this.appendChild(codeBlock, codeContent)
firstLine.functionType = 'codeLine'
this.appendChild(codeBlock, firstLine)
this.appendChild(block, inputBlock) this.appendChild(block, inputBlock)
this.appendChild(block, codeBlock) this.appendChild(block, codeBlock)
const { key } = firstLine const { key } = codeContent
const offset = code.length const offset = code.length
this.cursor = { this.cursor = {
start: { key, offset }, start: { key, offset },

View File

@ -1,4 +1,3 @@
const LINE_BREAKS_REG = /\n/
const FUNCTION_TYPE_LANG = { const FUNCTION_TYPE_LANG = {
multiplemath: 'latex', multiplemath: 'latex',
flowchart: 'yaml', flowchart: 'yaml',
@ -33,22 +32,20 @@ const containerCtrl = ContentState => {
this.appendChild(preBlock, codeBlock) this.appendChild(preBlock, codeBlock)
if (typeof value === 'string' && value) { if (typeof value === 'string' && value) {
value.replace(/^\s+/, '').split(LINE_BREAKS_REG).forEach(line => { value = value.replace(/^\s+/, '')
const codeLine = this.createBlock('span', { const codeContent = this.createBlock('span', {
text: line, text: value,
functionType: 'codeLine', lang,
lang functionType: 'codeContent'
})
this.appendChild(codeBlock, codeLine)
}) })
this.appendChild(codeBlock, codeContent)
} else { } else {
const emptyLine = this.createBlock('span', { const emptyCodeContent = this.createBlock('span', {
functionType: 'codeLine', functionType: 'codeContent',
lang lang
}) })
this.appendChild(codeBlock, emptyLine) this.appendChild(codeBlock, emptyCodeContent)
} }
const preview = this.createBlock('div', { const preview = this.createBlock('div', {

View File

@ -1,5 +1,6 @@
import selection from '../selection' import selection from '../selection'
import { CLASS_OR_ID } from '../config' import { CLASS_OR_ID } from '../config'
import { escapeHtml } from '../utils'
import { getSanitizeHtml } from '../utils/exportHtml' import { getSanitizeHtml } from '../utils/exportHtml'
import ExportMarkdown from '../utils/exportMarkdown' import ExportMarkdown from '../utils/exportMarkdown'
import marked from '../parser/marked' import marked from '../parser/marked'
@ -34,6 +35,19 @@ const copyCutCtrl = ContentState => {
} }
ContentState.prototype.getClipBoradData = function () { ContentState.prototype.getClipBoradData = function () {
const { start, end } = selection.getCursorRange()
if (start.key === end.key) {
const startBlock = this.getBlock(start.key)
const { type, text, functionType } = startBlock
// Fix issue #942
if (type === 'span' && functionType === 'codeContent') {
const selectedText = escapeHtml(text.substring(start.offset, end.offset))
return {
html: marked(selectedText),
text: selectedText
}
}
}
const html = selection.getSelectionHtml() const html = selection.getSelectionHtml()
const wrapper = document.createElement('div') const wrapper = document.createElement('div')
wrapper.innerHTML = html wrapper.innerHTML = html
@ -109,8 +123,8 @@ const copyCutCtrl = ContentState => {
const id = cf.id const id = cf.id
const block = this.getBlock(id) const block = this.getBlock(id)
const language = block.lang || '' const language = block.lang || ''
const selectedCodeLines = cf.querySelectorAll('.ag-code-line') const codeContent = cf.querySelector('.ag-code-content')
const value = Array.from(selectedCodeLines).map(codeLine => codeLine.textContent).join('\n') const value = escapeHtml(codeContent.textContent)
cf.innerHTML = `<code class="language-${language}">${value}</code>` cf.innerHTML = `<code class="language-${language}">${value}</code>`
} }
@ -125,10 +139,9 @@ const copyCutCtrl = ContentState => {
const htmlBlock = wrapper.querySelectorAll('figure[data-role=\'HTML\']') const htmlBlock = wrapper.querySelectorAll('figure[data-role=\'HTML\']')
for (const hb of htmlBlock) { for (const hb of htmlBlock) {
const selectedCodeLines = hb.querySelectorAll('span.ag-code-line') const codeContent = hb.querySelector('.ag-code-content')
const value = Array.from(selectedCodeLines).map(codeLine => codeLine.textContent).join('\n')
const pre = document.createElement('pre') const pre = document.createElement('pre')
pre.textContent = value pre.textContent = codeContent.textContent
hb.replaceWith(pre) hb.replaceWith(pre)
} }
@ -142,8 +155,8 @@ const copyCutCtrl = ContentState => {
for (const mb of mathBlock) { for (const mb of mathBlock) {
const preElement = mb.querySelector('pre[data-role]') const preElement = mb.querySelector('pre[data-role]')
const functionType = preElement.getAttribute('data-role') const functionType = preElement.getAttribute('data-role')
const selectedCodeLines = mb.querySelectorAll('span.ag-code-line') const codeContent = mb.querySelector('.ag-code-content')
const value = Array.from(selectedCodeLines).map(codeLine => codeLine.textContent).join('\n') const value = codeContent.textContent
let pre let pre
switch (functionType) { switch (functionType) {
case 'multiplemath': case 'multiplemath':
@ -165,7 +178,6 @@ const copyCutCtrl = ContentState => {
let htmlData = wrapper.innerHTML let htmlData = wrapper.innerHTML
const textData = this.htmlToMarkdown(htmlData) const textData = this.htmlToMarkdown(htmlData)
htmlData = marked(textData) htmlData = marked(textData)
return { html: htmlData, text: textData } return { html: htmlData, text: textData }
} }

View File

@ -33,10 +33,11 @@ const deleteCtrl = ContentState => {
) { ) {
event.preventDefault() event.preventDefault()
if (nextBlock && /h\d|span/.test(nextBlock.type)) { if (nextBlock && /h\d|span/.test(nextBlock.type)) {
if (nextBlock.functionType === 'codeLine' && nextBlock.nextSibling) { // if cursor at the end of code block-language input, do nothing!
// if code block more than one line, do nothing! if (nextBlock.functionType === 'codeContent' && startBlock.functionType === 'languageInput') {
return return
} }
startBlock.text += nextBlock.text startBlock.text += nextBlock.text
const toBeRemoved = [nextBlock] const toBeRemoved = [nextBlock]

View File

@ -237,31 +237,21 @@ const enterCtrl = ContentState => {
} }
return this.partialRender() return this.partialRender()
} else if ( } else if (
block.type === 'span' && block.functionType === 'codeLine' block.type === 'span' && block.functionType === 'codeContent'
) { ) {
const { text } = block const { text, key } = block
const newLineText = text.substring(start.offset)
const autoIndent = checkAutoIndent(text, start.offset) const autoIndent = checkAutoIndent(text, start.offset)
const indent = getIndentSpace(text) const indent = getIndentSpace(text)
block.text = text.substring(0, start.offset) block.text = text.substring(0, start.offset) +
const newLine = this.createBlock('span', { '\n' +
text: `${indent}${newLineText}`, (autoIndent ? indent + ' '.repeat(this.tabSize) + '\n' : '') +
functionType: block.functionType, indent +
lang: block.lang text.substring(start.offset)
})
let offset = start.offset + 1 + indent.length
this.insertAfter(newLine, block)
let { key } = newLine
let offset = indent.length
if (autoIndent) { if (autoIndent) {
const emptyLine = this.createBlock('span', { offset += this.tabSize
text: indent + ' '.repeat(this.tabSize)
})
emptyLine.functionType = block.functionType
emptyLine.lang = block.lang
this.insertAfter(emptyLine, block)
key = emptyLine.key
offset = indent.length + this.tabSize
} }
this.cursor = { this.cursor = {

View File

@ -16,7 +16,7 @@ const imageCtrl = ContentState => {
if ( if (
block.type === 'span' && block.type === 'span' &&
( (
block.functionType === 'codeLine' || block.functionType === 'codeContent' ||
block.functionType === 'languageInput' || block.functionType === 'languageInput' ||
block.functionType === 'thematicBreakLine' block.functionType === 'thematicBreakLine'
) )

View File

@ -28,6 +28,7 @@ import linkCtrl from './linkCtrl'
import dragDropCtrl from './dragDropCtrl' import dragDropCtrl from './dragDropCtrl'
import importMarkdown from '../utils/importMarkdown' import importMarkdown from '../utils/importMarkdown'
import Cursor from '../selection/cursor' import Cursor from '../selection/cursor'
import escapeCharactersMap, { escapeCharacters } from '../parser/escapeCharacter'
const prototypes = [ const prototypes = [
tabCtrl, tabCtrl,
@ -253,6 +254,13 @@ class ContentState {
blockData.functionType = 'paragraphContent' blockData.functionType = 'paragraphContent'
} }
if (extras.functionType === 'codeContent' && extras.text) {
const CHAR_REG = new RegExp(`(${escapeCharacters.join('|')})`, 'gi')
extras.text = extras.text.replace(CHAR_REG, (_, p) => {
return escapeCharactersMap[p]
})
}
Object.assign(blockData, extras) Object.assign(blockData, extras)
return blockData return blockData
} }

View File

@ -77,7 +77,7 @@ const inputCtrl = ContentState => {
return false return false
} }
ContentState.prototype.inputHandler = function (event) { ContentState.prototype.inputHandler = function (event, notEqual = false) {
const { start, end } = selection.getCursorRange() const { start, end } = selection.getCursorRange()
if (!start || !end) { if (!start || !end) {
return return
@ -86,6 +86,27 @@ const inputCtrl = ContentState => {
const key = start.key const key = start.key
const block = this.getBlock(key) const block = this.getBlock(key)
const paragraph = document.querySelector(`#${key}`) const paragraph = document.querySelector(`#${key}`)
// Fix issue 1447
// Fixme: any better solution?
if (
oldStart.key === oldEnd.key &&
oldStart.offset === oldEnd.offset &&
block.text.endsWith('\n') &&
oldStart.offset === block.text.length &&
event.inputType === 'insertText'
) {
event.preventDefault()
block.text += event.data
const offset = block.text.length
this.cursor = {
start: { key, offset },
end: { key, offset }
}
this.singleRender(block)
return this.inputHandler(event, true)
}
let text = getTextContent(paragraph, [CLASS_OR_ID.AG_MATH_RENDER, CLASS_OR_ID.AG_RUBY_RENDER]) let text = getTextContent(paragraph, [CLASS_OR_ID.AG_MATH_RENDER, CLASS_OR_ID.AG_RUBY_RENDER])
let needRender = false let needRender = false
@ -123,7 +144,7 @@ const inputCtrl = ContentState => {
} }
// auto pair (not need to auto pair in math block) // auto pair (not need to auto pair in math block)
if (block && block.text !== text) { if (block && (block.text !== text || notEqual)) {
if ( if (
start.key === end.key && start.key === end.key &&
start.offset === end.offset && start.offset === end.offset &&
@ -173,7 +194,7 @@ const inputCtrl = ContentState => {
((autoPairQuote && /[']{1}/.test(inputChar) && !(/[a-zA-Z\d]{1}/.test(preInputChar))) || ((autoPairQuote && /[']{1}/.test(inputChar) && !(/[a-zA-Z\d]{1}/.test(preInputChar))) ||
(autoPairQuote && /["]{1}/.test(inputChar)) || (autoPairQuote && /["]{1}/.test(inputChar)) ||
(autoPairBracket && /[\{\[\(]{1}/.test(inputChar)) || (autoPairBracket && /[\{\[\(]{1}/.test(inputChar)) ||
(block.functionType !== 'codeLine' && !isInInlineMath && !isInInlineCode && autoPairMarkdownSyntax && /[*$`~_]{1}/.test(inputChar))) (block.functionType !== 'codeContent' && !isInInlineMath && !isInInlineCode && autoPairMarkdownSyntax && /[*$`~_]{1}/.test(inputChar)))
) { ) {
needRender = true needRender = true
text = BRACKET_HASH[event.data] text = BRACKET_HASH[event.data]
@ -250,8 +271,7 @@ const inputCtrl = ContentState => {
this.muya.eventCenter.dispatch('muya-quick-insert', reference, block, !!checkQuickInsert) this.muya.eventCenter.dispatch('muya-quick-insert', reference, block, !!checkQuickInsert)
// Update preview content of math block if (block && block.type === 'span' && block.functionType === 'codeContent') {
if (block && block.type === 'span' && block.functionType === 'codeLine') {
needRender = true needRender = true
} }

View File

@ -2,8 +2,6 @@ import selection from '../selection'
import { PARAGRAPH_TYPES, DEFAULT_TURNDOWN_CONFIG } from '../config' import { PARAGRAPH_TYPES, DEFAULT_TURNDOWN_CONFIG } from '../config'
import ExportMarkdown from '../utils/exportMarkdown' import ExportMarkdown from '../utils/exportMarkdown'
const LINE_BREAKS_REG = /\n/
// get header level // get header level
// eg: h1 => 1 // eg: h1 => 1
// h2 => 2 // h2 => 2
@ -99,15 +97,15 @@ const paragraphCtrl = ContentState => {
const codeBlock = this.createBlock('code', { const codeBlock = this.createBlock('code', {
lang lang
}) })
const emptyLine = this.createBlock('span', { const emptyCodeContent = this.createBlock('span', {
functionType: 'codeLine', functionType: 'codeContent',
lang lang
}) })
this.appendChild(codeBlock, emptyLine) this.appendChild(codeBlock, emptyCodeContent)
this.appendChild(frontMatter, codeBlock) this.appendChild(frontMatter, codeBlock)
this.insertBefore(frontMatter, firstBlock) this.insertBefore(frontMatter, firstBlock)
const { key } = emptyLine const { key } = emptyCodeContent
const offset = 0 const offset = 0
this.cursor = { this.cursor = {
start: { key, offset }, start: { key, offset },
@ -248,39 +246,21 @@ const paragraphCtrl = ContentState => {
// change fenced code block to p paragraph // change fenced code block to p paragraph
if (affiliation.length && affiliation[0].type === 'pre' && /code/.test(affiliation[0].functionType)) { if (affiliation.length && affiliation[0].type === 'pre' && /code/.test(affiliation[0].functionType)) {
const preBlock = affiliation[0] const preBlock = affiliation[0]
const codeLines = preBlock.children[1].children const codeContent = preBlock.children[1].children[0]
preBlock.type = 'p' preBlock.type = 'p'
preBlock.children = [] preBlock.children = []
const newParagraphBlock = this.createBlockP(codeLines.map(l => l.text).join('\n')) const newParagraphBlock = this.createBlockP(codeContent.text)
this.insertBefore(newParagraphBlock, preBlock) this.insertBefore(newParagraphBlock, preBlock)
this.removeBlock(preBlock) this.removeBlock(preBlock)
const { start, end } = this.cursor const { start, end } = this.cursor
const key = newParagraphBlock.children[0].key const key = newParagraphBlock.children[0].key
let startOffset = 0
let endOffset = 0
let startStop = false
let endStop = false
for (const line of codeLines) {
if (line.key !== start.key && !startStop) {
startOffset += line.text.length + 1
} else {
startOffset += start.offset
startStop = true
}
if (line.key !== end.key && !endStop) {
endOffset += line.text.length + 1
} else {
endOffset += end.offset
endStop = true
}
}
this.cursor = { this.cursor = {
start: { key, offset: startOffset }, start: { key, offset: start.offset },
end: { key, offset: endOffset } end: { key, offset: end.offset }
} }
} else { } else {
if (start.key === end.key) { if (start.key === end.key) {
@ -293,24 +273,20 @@ const paragraphCtrl = ContentState => {
}) })
const codeBlock = this.createBlock('code', { const codeBlock = this.createBlock('code', {
lang: '' lang
}) })
const inputBlock = this.createBlock('span', { const inputBlock = this.createBlock('span', {
functionType: 'languageInput' functionType: 'languageInput'
}) })
const codes = startBlock.text.split('\n') const codeContent = this.createBlock('span', {
text: startBlock.text,
for (const code of codes) { lang,
const codeLine = this.createBlock('span', { functionType: 'codeContent'
text: code, })
functionType: 'codeLine',
lang
})
this.appendChild(codeBlock, codeLine)
}
this.appendChild(codeBlock, codeContent)
this.appendChild(preBlock, inputBlock) this.appendChild(preBlock, inputBlock)
this.appendChild(preBlock, codeBlock) this.appendChild(preBlock, codeBlock)
this.insertBefore(preBlock, anchorBlock) this.insertBefore(preBlock, anchorBlock)
@ -345,20 +321,15 @@ const paragraphCtrl = ContentState => {
const listIndentation = this.listIndentation const listIndentation = this.listIndentation
const markdown = new ExportMarkdown(children.slice(startIndex, endIndex + 1), listIndentation).generate() const markdown = new ExportMarkdown(children.slice(startIndex, endIndex + 1), listIndentation).generate()
const codeContent = this.createBlock('span', {
markdown.split(LINE_BREAKS_REG).forEach(text => { text: markdown,
const codeLine = this.createBlock('span', { lang,
text, functionType: 'codeContent'
lang,
functionType: 'codeLine'
})
this.appendChild(codeBlock, codeLine)
}) })
const inputBlock = this.createBlock('span', { const inputBlock = this.createBlock('span', {
functionType: 'languageInput' functionType: 'languageInput'
}) })
this.appendChild(codeBlock, codeContent)
this.appendChild(preBlock, inputBlock) this.appendChild(preBlock, inputBlock)
this.appendChild(preBlock, codeBlock) this.appendChild(preBlock, codeBlock)
this.insertAfter(preBlock, referBlock) this.insertAfter(preBlock, referBlock)
@ -774,20 +745,19 @@ const paragraphCtrl = ContentState => {
} }
// Handler selectAll in code block. only select all the code block conent. // Handler selectAll in code block. only select all the code block conent.
// `code block` here is Math, HTML, BLOCK CODE, Mermaid, vega-lite, flowchart, front-matter etc... // `code block` here is Math, HTML, BLOCK CODE, Mermaid, vega-lite, flowchart, front-matter etc...
if (startBlock.type === 'span' && startBlock.functionType === 'codeLine') { if (startBlock.type === 'span' && startBlock.functionType === 'codeContent') {
const codeBlock = this.getParent(startBlock) const { key } = startBlock
const firstCodeLine = this.firstInDescendant(codeBlock)
const lastCodeLine = this.lastInDescendant(codeBlock)
this.cursor = { this.cursor = {
start: { start: {
key: firstCodeLine.key, key,
offset: 0 offset: 0
}, },
end: { end: {
key: lastCodeLine.key, key,
offset: lastCodeLine.text.length offset: startBlock.text.length
} }
} }
return this.partialRender() return this.partialRender()
} }
// Handler language input, only select language info only... // Handler language input, only select language info only...

View File

@ -314,42 +314,18 @@ const pasteCtrl = ContentState => {
return return
} }
if (startBlock.type === 'span' && startBlock.functionType === 'codeLine') { if (startBlock.type === 'span' && startBlock.functionType === 'codeContent') {
let referenceBlock = startBlock
const blockText = startBlock.text const blockText = startBlock.text
const prePartText = blockText.substring(0, start.offset) const prePartText = blockText.substring(0, start.offset)
const postPartText = blockText.substring(end.offset) const postPartText = blockText.substring(end.offset)
const textList = text.split(LINE_BREAKS_REG) startBlock.text = prePartText + text + postPartText
if (textList.length > 1) { const { key } = startBlock
textList.forEach((line, i) => { const offset = start.offset + text.length
if (i === 0) { this.cursor = {
startBlock.text = prePartText + line start: { key, offset },
} else { end: { key, offset }
line = i === textList.length - 1 ? line + postPartText : line
const lineBlock = this.createBlock('span', { text: line })
lineBlock.functionType = startBlock.functionType
lineBlock.lang = startBlock.lang
this.insertAfter(lineBlock, referenceBlock)
referenceBlock = lineBlock
if (i === textList.length - 1) {
const { key } = lineBlock
const offset = line.length
this.cursor = {
start: { key, offset },
end: { key, offset }
}
}
}
})
} else {
startBlock.text = prePartText + text + postPartText
const key = startBlock.key
const offset = start.offset + text.length
this.cursor = {
start: { key, offset },
end: { key, offset }
}
} }
return this.partialRender() return this.partialRender()
} }

View File

@ -292,7 +292,7 @@ const tabCtrl = ContentState => {
start.key === end.key && start.key === end.key &&
start.offset === end.offset && start.offset === end.offset &&
HAS_TEXT_BLOCK_REG.test(startBlock.type) && HAS_TEXT_BLOCK_REG.test(startBlock.type) &&
startBlock.functionType !== 'codeLine' && // code line has no inline syntax startBlock.functionType !== 'codeContent' && // code content has no inline syntax
startBlock.functionType !== 'languageInput' // language input textarea has no inline syntax startBlock.functionType !== 'languageInput' // language input textarea has no inline syntax
) { ) {
const { text, key } = startBlock const { text, key } = startBlock
@ -312,7 +312,7 @@ const tabCtrl = ContentState => {
start.key === end.key && start.key === end.key &&
start.offset === end.offset && start.offset === end.offset &&
startBlock.type === 'span' && startBlock.type === 'span' &&
(!startBlock.functionType || startBlock.functionType === 'codeLine' && /markup|html|xml|svg|mathml/.test(startBlock.lang)) (!startBlock.functionType || startBlock.functionType === 'codeContent' && /markup|html|xml|svg|mathml/.test(startBlock.lang))
) { ) {
const { text } = startBlock const { text } = startBlock
const lastWordBeforeCursor = text.substring(0, start.offset).split(/\s+/).pop() const lastWordBeforeCursor = text.substring(0, start.offset).split(/\s+/).pop()

View File

@ -49,7 +49,7 @@ const tableBlockCtrl = ContentState => {
const { type, functionType } = block const { type, functionType } = block
switch (type) { switch (type) {
case 'span': case 'span':
if (functionType === 'codeLine') { if (functionType === 'codeContent') {
return this.closest(block, 'figure') || this.closest(block, 'pre') return this.closest(block, 'figure') || this.closest(block, 'pre')
} else { } else {
return this.getParent(block) return this.getParent(block)

View File

@ -68,7 +68,7 @@ const updateCtrl = ContentState => {
ContentState.prototype.checkInlineUpdate = function (block) { ContentState.prototype.checkInlineUpdate = function (block) {
// table cell can not have blocks in it // table cell can not have blocks in it
if (/th|td|figure/.test(block.type)) return false if (/th|td|figure/.test(block.type)) return false
if (/codeLine|languageInput/.test(block.functionType)) return false if (/codeContent|languageInput/.test(block.functionType)) return false
let line = null let line = null
const { text } = block const { text } = block
@ -84,7 +84,7 @@ const updateCtrl = ContentState => {
switch (true) { switch (true) {
case (!!hr && new Set(hr.split('').filter(i => /\S/.test(i))).size === 1): case (!!hr && new Set(hr.split('').filter(i => /\S/.test(i))).size === 1):
return this.updateHr(block, hr, line) return this.updateThematicBreak(block, hr, line)
case !!bullet: case !!bullet:
return this.updateList(block, 'bullet', bullet, line) return this.updateList(block, 'bullet', bullet, line)
@ -115,7 +115,7 @@ const updateCtrl = ContentState => {
} }
// Thematic break // Thematic break
ContentState.prototype.updateHr = function (block, marker, line) { ContentState.prototype.updateThematicBreak = function (block, marker, line) {
// If the block is already thematic break, no need to update. // If the block is already thematic break, no need to update.
if (block.type === 'hr') return null if (block.type === 'hr') return null
const text = line.text const text = line.text
@ -124,9 +124,10 @@ const updateCtrl = ContentState => {
let thematicLine = '' let thematicLine = ''
const postParagraphLines = [] const postParagraphLines = []
let thematicLineHasPushed = false let thematicLineHasPushed = false
for (const l of lines) { for (const l of lines) {
if (/ {0,3}(?:\\* *\\* *\\*|- *- *-|_ *_ *_)[ \\*\\-\\_]*$/.test(l) && !thematicLineHasPushed) { /* eslint-disable no-useless-escape */
if (/ {0,3}(?:\* *\* *\*|- *- *-|_ *_ *_)[ \*\-\_]*$/.test(l) && !thematicLineHasPushed) {
/* eslint-enable no-useless-escape */
thematicLine = l thematicLine = l
thematicLineHasPushed = true thematicLineHasPushed = true
} else if (!thematicLineHasPushed) { } else if (!thematicLineHasPushed) {
@ -155,9 +156,12 @@ const updateCtrl = ContentState => {
this.removeBlock(block) this.removeBlock(block)
const { start, end } = this.cursor const { start, end } = this.cursor
const key = thematicBlock.children[0].key const key = thematicBlock.children[0].key
const preParagraphLength = preParagraphLines.reduce((acc, i) => acc + i.length + 1, 0) // Add one, because the `\n`
const startOffset = start.offset - preParagraphLength
const endOffset = end.offset - preParagraphLength
this.cursor = { this.cursor = {
start: { key, offset: start.offset }, start: { key, offset: startOffset },
end: { key, offset: end.offset } end: { key, offset: endOffset }
} }
return thematicBlock return thematicBlock
} }
@ -519,15 +523,16 @@ const updateCtrl = ContentState => {
} }
ContentState.prototype.updateIndentCode = function (block, line) { ContentState.prototype.updateIndentCode = function (block, line) {
const lang = ''
const codeBlock = this.createBlock('code', { const codeBlock = this.createBlock('code', {
lang: '' lang
}) })
const inputBlock = this.createBlock('span', { const inputBlock = this.createBlock('span', {
functionType: 'languageInput' functionType: 'languageInput'
}) })
const preBlock = this.createBlock('pre', { const preBlock = this.createBlock('pre', {
functionType: 'indentcode', functionType: 'indentcode',
lang: '' lang
}) })
const text = line ? line.text : block.text const text = line ? line.text : block.text
@ -545,15 +550,13 @@ const updateCtrl = ContentState => {
paragraphLines.push(l) paragraphLines.push(l)
} }
} }
codeLines.forEach(text => { const codeContent = this.createBlock('span', {
const codeLine = this.createBlock('span', { text: codeLines.join('\n'),
text, functionType: 'codeContent',
functionType: 'codeLine', lang
lang: ''
})
this.appendChild(codeBlock, codeLine)
}) })
this.appendChild(codeBlock, codeContent)
this.appendChild(preBlock, inputBlock) this.appendChild(preBlock, inputBlock)
this.appendChild(preBlock, codeBlock) this.appendChild(preBlock, codeBlock)
this.insertBefore(preBlock, block) this.insertBefore(preBlock, block)

View File

@ -275,7 +275,7 @@ class Keyboard {
} }
const block = contentState.getBlock(anchor.key) const block = contentState.getBlock(anchor.key)
if (anchor.key === focus.key && anchor.offset !== focus.offset && block.functionType !== 'codeLine') { if (anchor.key === focus.key && anchor.offset !== focus.offset && block.functionType !== 'codeContent') {
const reference = contentState.getPositionReference() const reference = contentState.getPositionReference()
const { formats } = contentState.selectionFormats() const { formats } = contentState.selectionFormats()
eventCenter.dispatch('muya-format-picker', { reference, formats }) eventCenter.dispatch('muya-format-picker', { reference, formats })

View File

@ -56,7 +56,7 @@ Renderer.prototype.code = function (code, infostring, escaped, codeBlockStyle) {
className + className +
'">' + '">' +
(escaped ? code : escape(code, true)) + (escaped ? code : escape(code, true)) +
'\n</code></pre>\n' '</code></pre>\n'
} }
Renderer.prototype.blockquote = function (quote) { Renderer.prototype.blockquote = function (quote) {

View File

@ -14,21 +14,40 @@ const MARKER_HASK = {
"'": `%${getLongUniqueId()}%` "'": `%${getLongUniqueId()}%`
} }
const getHighlightHtml = (text, highlights, escape = false) => { const getHighlightHtml = (text, highlights, escape = false, handleLineEnding = false) => {
let code = '' let code = ''
let pos = 0 let pos = 0
const getEscapeHTML = (className, content) => {
return `${MARKER_HASK['<']}span class=${MARKER_HASK['"']}${className}${MARKER_HASK['"']}${MARKER_HASK['>']}${content}${MARKER_HASK['<']}/span${MARKER_HASK['>']}`
}
for (const highlight of highlights) { for (const highlight of highlights) {
const { start, end, active } = highlight const { start, end, active } = highlight
code += text.substring(pos, start) code += text.substring(pos, start)
const className = active ? 'ag-highlight' : 'ag-selection' const className = active ? 'ag-highlight' : 'ag-selection'
let highlightContent = text.substring(start, end)
if (handleLineEnding && text.endsWith('\n') && end === text.length) {
highlightContent = highlightContent.substring(start, end - 1) +
(escape
? getEscapeHTML('ag-line-end', '\n')
: '<span class="ag-line-end">\n</span>')
}
code += escape code += escape
? `${MARKER_HASK['<']}span class=${MARKER_HASK['"']}${className}${MARKER_HASK['"']}${MARKER_HASK['>']}${text.substring(start, end)}${MARKER_HASK['<']}/span${MARKER_HASK['>']}` ? getEscapeHTML(className, highlightContent)
: `<span class="${className}">${text.substring(start, end)}</span>` : `<span class="${className}">${highlightContent}</span>`
pos = end pos = end
} }
if (pos !== text.length) { if (pos !== text.length) {
code += text.substring(pos) if (handleLineEnding && text.endsWith('\n')) {
code += text.substring(pos, text.length - 1) +
(escape
? getEscapeHTML('ag-line-end', '\n')
: '<span class="ag-line-end">\n</span>')
} else {
code += text.substring(pos)
}
} }
return code return code
} }
@ -81,7 +100,7 @@ export default function renderLeafBlock (block, activeBlocks, matches, useCache
tokens = this.tokenCache.get(text) tokens = this.tokenCache.get(text)
} else if ( } else if (
HAS_TEXT_BLOCK_REG.test(type) && HAS_TEXT_BLOCK_REG.test(type) &&
functionType !== 'codeLine' && functionType !== 'codeContent' &&
functionType !== 'languageInput' functionType !== 'languageInput'
) { ) {
const hasBeginRules = type === 'span' const hasBeginRules = type === 'span'
@ -197,8 +216,8 @@ export default function renderLeafBlock (block, activeBlocks, matches, useCache
selector += `.${CLASS_OR_ID.AG_CHECKBOX_CHECKED}` selector += `.${CLASS_OR_ID.AG_CHECKBOX_CHECKED}`
} }
children = '' children = ''
} else if (type === 'span' && functionType === 'codeLine') { } else if (type === 'span' && functionType === 'codeContent') {
const code = escapeHtml(getHighlightHtml(text, highlights, true)) const code = escapeHtml(getHighlightHtml(text, highlights, true, true))
.replace(new RegExp(MARKER_HASK['<'], 'g'), '<') .replace(new RegExp(MARKER_HASK['<'], 'g'), '<')
.replace(new RegExp(MARKER_HASK['>'], 'g'), '>') .replace(new RegExp(MARKER_HASK['>'], 'g'), '>')
.replace(new RegExp(MARKER_HASK['"'], 'g'), '"') .replace(new RegExp(MARKER_HASK['"'], 'g'), '"')

View File

@ -419,6 +419,7 @@ class Selection {
offset offset
} }
} }
const childNodes = node.childNodes const childNodes = node.childNodes
const len = childNodes.length const len = childNodes.length
let i let i
@ -429,6 +430,7 @@ class Selection {
if (child.classList && child.classList.contains(CLASS_OR_ID.AG_FRONT_ICON)) { if (child.classList && child.classList.contains(CLASS_OR_ID.AG_FRONT_ICON)) {
continue continue
} }
if (count + textLength >= offset) { if (count + textLength >= offset) {
if ( if (
child.classList && child.classList.contains('ag-inline-image') child.classList && child.classList.contains('ag-inline-image')
@ -536,8 +538,10 @@ class Selection {
const anchorParagraph = findNearestParagraph(anchorNode) const anchorParagraph = findNearestParagraph(anchorNode)
const focusParagraph = findNearestParagraph(focusNode) const focusParagraph = findNearestParagraph(focusNode)
let aOffset = getOffsetOfParagraph(anchorNode, anchorParagraph) + anchorOffset let aOffset = getOffsetOfParagraph(anchorNode, anchorParagraph) + anchorOffset
let fOffset = getOffsetOfParagraph(focusNode, focusParagraph) + focusOffset let fOffset = getOffsetOfParagraph(focusNode, focusParagraph) + focusOffset
// fix input after image. // fix input after image.
if ( if (
anchorNode === focusNode && anchorNode === focusNode &&
@ -576,6 +580,7 @@ class Selection {
} }
const anchor = { key: anchorParagraph.id, offset: aOffset } const anchor = { key: anchorParagraph.id, offset: aOffset }
const focus = { key: focusParagraph.id, offset: fOffset } const focus = { key: focusParagraph.id, offset: fOffset }
const result = new Cursor({ anchor, focus }) const result = new Cursor({ anchor, focus })

View File

@ -247,7 +247,8 @@ class ExportMarkdown {
normalizeCodeBlock (block, indent) { normalizeCodeBlock (block, indent) {
const result = [] const result = []
const textList = block.children[1].children.map(codeLine => codeLine.text) const codeContent = block.children[1].children[0]
const textList = codeContent.text.split('\n')
const { functionType } = block const { functionType } = block
if (functionType === 'fencecode') { if (functionType === 'fencecode') {
result.push(`${indent}${block.lang ? '```' + block.lang + '\n' : '```\n'}`) result.push(`${indent}${block.lang ? '```' + block.lang + '\n' : '```\n'}`)
@ -266,9 +267,10 @@ class ExportMarkdown {
normalizeHTML (block, indent) { // figure normalizeHTML (block, indent) { // figure
const result = [] const result = []
const codeLines = block.children[0].children[0].children const codeContentText = block.children[0].children[0].children[0].text
for (const line of codeLines) { const lines = codeContentText.split('\n')
result.push(`${indent}${line.text}\n`) for (const line of lines) {
result.push(`${indent}${line}\n`)
} }
return result.join('') return result.join('')
} }

View File

@ -11,8 +11,6 @@ import { loadLanguage } from '../prism/index'
// To be disabled rules when parse markdown, Because content state don't need to parse inline rules // To be disabled rules when parse markdown, Because content state don't need to parse inline rules
import { CURSOR_ANCHOR_DNA, CURSOR_FOCUS_DNA } from '../config' import { CURSOR_ANCHOR_DNA, CURSOR_FOCUS_DNA } from '../config'
const LINE_BREAKS_REG = /\n/
// Just because turndown change `\n`(soft line break) to space, So we add `span.ag-soft-line-break` to workaround. // Just because turndown change `\n`(soft line break) to space, So we add `span.ag-soft-line-break` to workaround.
const turnSoftBreakToSpan = html => { const turnSoftBreakToSpan = html => {
const parser = new DOMParser() const parser = new DOMParser()
@ -23,7 +21,7 @@ const turnSoftBreakToSpan = html => {
const root = doc.querySelector('#turn-root') const root = doc.querySelector('#turn-root')
const travel = childNodes => { const travel = childNodes => {
for (const node of childNodes) { for (const node of childNodes) {
if (node.nodeType === 3) { if (node.nodeType === 3 && node.parentNode.tagName !== 'CODE') {
let startLen = 0 let startLen = 0
let endLen = 0 let endLen = 0
const text = node.nodeValue.replace(/^(\n+)/, (_, p) => { const text = node.nodeValue.replace(/^(\n+)/, (_, p) => {
@ -89,27 +87,25 @@ const importRegister = ContentState => {
case 'frontmatter': { case 'frontmatter': {
const { lang, style } = token const { lang, style } = token
value = token.text value = token.text
.replace(/^\s+/, '')
.replace(/\s$/, '')
block = this.createBlock('pre', { block = this.createBlock('pre', {
functionType: token.type, functionType: token.type,
lang, lang,
style style
}) })
const codeBlock = this.createBlock('code', { const codeBlock = this.createBlock('code', {
lang lang
}) })
value
.replace(/^\s+/, '')
.replace(/\s$/, '')
.split(LINE_BREAKS_REG).forEach(line => {
const codeLine = this.createBlock('span', {
text: line,
lang,
functionType: 'codeLine'
})
this.appendChild(codeBlock, codeLine) const codeContent = this.createBlock('span', {
}) text: value,
lang,
functionType: 'codeContent'
})
this.appendChild(codeBlock, codeContent)
this.appendChild(block, codeBlock) this.appendChild(block, codeBlock)
this.appendChild(parentList[0], block) this.appendChild(parentList[0], block)
break break
@ -175,13 +171,10 @@ const importRegister = ContentState => {
const codeBlock = this.createBlock('code', { const codeBlock = this.createBlock('code', {
lang lang
}) })
value.split(LINE_BREAKS_REG).forEach(line => { const codeContent = this.createBlock('span', {
const codeLine = this.createBlock('span', { text: value,
text: line lang,
}) functionType: 'codeContent'
codeLine.lang = lang
codeLine.functionType = 'codeLine'
this.appendChild(codeBlock, codeLine)
}) })
const inputBlock = this.createBlock('span', { const inputBlock = this.createBlock('span', {
text: lang, text: lang,
@ -205,6 +198,7 @@ const importRegister = ContentState => {
}) })
} }
this.appendChild(codeBlock, codeContent)
this.appendChild(block, inputBlock) this.appendChild(block, inputBlock)
this.appendChild(block, codeBlock) this.appendChild(block, codeBlock)
this.appendChild(parentList[0], block) this.appendChild(parentList[0], block)
@ -364,6 +358,7 @@ const importRegister = ContentState => {
html = html.replace(/<span>&nbsp;<\/span>/g, String.fromCharCode(160)) html = html.replace(/<span>&nbsp;<\/span>/g, String.fromCharCode(160))
html = turnSoftBreakToSpan(html) html = turnSoftBreakToSpan(html)
const markdown = turndownService.turndown(html) const markdown = turndownService.turndown(html)
return markdown return markdown
} }

View File

@ -1,5 +1,4 @@
import TurndownService from 'turndown' import TurndownService from 'turndown'
import { CLASS_OR_ID, LINE_BREAK } from '../config'
import { identity } from './index' import { identity } from './index'
const turndownPluginGfm = require('joplin-turndown-plugin-gfm') const turndownPluginGfm = require('joplin-turndown-plugin-gfm')
@ -27,18 +26,6 @@ export const usePluginAddRules = (turndownService, keeps) => {
} }
}) })
// Add `LINE_BREAK` to the end of every code line but not the last line.
turndownService.addRule('codeLineBreak', {
filter (node, options) {
return (
node.nodeName === 'SPAN' && node.classList.contains(CLASS_OR_ID.AG_CODE_LINE) && node.nextElementSibling
)
},
replacement (content, node, options) {
return content + LINE_BREAK
}
})
turndownService.escape = identity turndownService.escape = identity
turndownService.keep(keeps) turndownService.keep(keeps)
} }

View File

@ -873,10 +873,10 @@
once "^1.4.0" once "^1.4.0"
universal-user-agent "^4.0.0" universal-user-agent "^4.0.0"
"@octokit/rest@^16.30.1": "@octokit/rest@^16.31.0":
version "16.30.1" version "16.31.0"
resolved "https://registry.npmjs.org/@octokit/rest/-/rest-16.30.1.tgz#03e6dfb93e9a9cd2b3bacb95c49a8c7923f42ad0" resolved "https://registry.npmjs.org/@octokit/rest/-/rest-16.31.0.tgz#97ceba8e9b6bfdaffa321d7022917053fcb7dc39"
integrity sha512-1n2QzTbbaBXNLpx7WHlcsSMdJvxSdKmerXQm+bMYlKDbQM19uq446ZpGs7Ynq5SsdLj1usIfgJ9gJf4LtcWkDw== integrity sha512-ZmMpc59N/Ju8FjN2qyOefB+vLppO/8uP/tPyvwEe7cQxdXvPx0OXL/OxDLib8tnT046AtgMNYaXH3FpZnrUdOA==
dependencies: dependencies:
"@octokit/request" "^5.0.0" "@octokit/request" "^5.0.0"
"@octokit/request-error" "^1.0.2" "@octokit/request-error" "^1.0.2"
@ -10216,6 +10216,14 @@ schema-utils@^2.2.0:
ajv "^6.10.2" ajv "^6.10.2"
ajv-keywords "^3.4.1" ajv-keywords "^3.4.1"
schema-utils@^2.4.1:
version "2.4.1"
resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-2.4.1.tgz#e89ade5d056dc8bcaca377574bb4a9c4e1b8be56"
integrity sha512-RqYLpkPZX5Oc3fw/kHHHyP56fg5Y+XBpIpV8nCg0znIALfq3OH+Ea9Hfeac9BAMwG5IICltiZ0vxFvJQONfA5w==
dependencies:
ajv "^6.10.2"
ajv-keywords "^3.4.1"
scope-css@^1.2.1: scope-css@^1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.npmjs.org/scope-css/-/scope-css-1.2.1.tgz#c35768bc900cad030a3e0d663a818c0f6a57f40e" resolved "https://registry.npmjs.org/scope-css/-/scope-css-1.2.1.tgz#c35768bc900cad030a3e0d663a818c0f6a57f40e"
@ -11690,14 +11698,14 @@ urix@^0.1.0:
resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
url-loader@^2.1.0: url-loader@^2.2.0:
version "2.1.0" version "2.2.0"
resolved "https://registry.npmjs.org/url-loader/-/url-loader-2.1.0.tgz#bcc1ecabbd197e913eca23f5e0378e24b4412961" resolved "https://registry.npmjs.org/url-loader/-/url-loader-2.2.0.tgz#af321aece1fd0d683adc8aaeb27829f29c75b46e"
integrity sha512-kVrp/8VfEm5fUt+fl2E0FQyrpmOYgMEkBsv8+UDP1wFhszECq5JyGF33I7cajlVY90zRZ6MyfgKXngLvHYZX8A== integrity sha512-G8nk3np8ZAnwhHXas1JxJEwJyQdqFXAKJehfgZ/XrC48volFBRtO+FIKtF2u0Ma3bw+4vnDVjHPAQYlF9p2vsw==
dependencies: dependencies:
loader-utils "^1.2.3" loader-utils "^1.2.3"
mime "^2.4.4" mime "^2.4.4"
schema-utils "^2.0.0" schema-utils "^2.4.1"
url-parse-lax@^3.0.0: url-parse-lax@^3.0.0:
version "3.0.0" version "3.0.0"