diff --git a/.eslintrc b/.eslintrc index 451640a0..e3924b6a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -18,3 +18,9 @@ rules: ignoreTemplateLiterals: true no-param-reassign: off + + no-restricted-syntax: + - error + - ForInStatement + - LabeledStatement + - WithStatement diff --git a/CHANGELOG.md b/CHANGELOG.md index a01961ca..a9985b3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Improve conversion performance by using `for-of` loop (40-70% faster) ([#79](https://github.com/marp-team/marpit/pull/79)) + ## v0.1.2 - 2018-09-20 ### Fixed diff --git a/src/element.js b/src/element.js index 6b7dc971..1feb802e 100644 --- a/src/element.js +++ b/src/element.js @@ -32,12 +32,12 @@ class Element { tag: { enumerable: true, value: tag }, }) - Object.keys(attributes).forEach(attr => { + for (const attr of Object.keys(attributes)) { Object.defineProperty(this, attr, { enumerable: true, value: attributes[attr], }) - }) + } Object.freeze(this) } diff --git a/src/helpers/inline_style.js b/src/helpers/inline_style.js index 6d2fe74d..8b4ed7a4 100644 --- a/src/helpers/inline_style.js +++ b/src/helpers/inline_style.js @@ -64,7 +64,9 @@ export default class InlineStyle { * The unexpected declarations will strip to prevent a style injection. */ toString() { - return Object.keys(this.decls).reduce((stt, prop) => { + let built = '' + + for (const prop of Object.keys(this.decls)) { let parsed try { @@ -73,14 +75,17 @@ export default class InlineStyle { }) } catch (e) { // A declaration that have value it cannot parse will ignore. - return stt } - parsed.each(node => { - if (node.type !== 'decl' || node.prop !== prop) node.remove() - }) + if (parsed) { + parsed.each(node => { + if (node.type !== 'decl' || node.prop !== prop) node.remove() + }) + + built += `${parsed.toString()};` + } + } - return `${stt}${parsed.toString()};` - }, '') + return built } } diff --git a/src/helpers/split.js b/src/helpers/split.js index 8e3bfd36..9a1711f8 100644 --- a/src/helpers/split.js +++ b/src/helpers/split.js @@ -10,21 +10,23 @@ * @returns {Array[]} Splited array. */ function split(arr, func, keepSplitedValue = false) { - return arr.reduce( - (ret, value) => { - /** - * Return true at the split point. - * - * @callback splitCallback - * @param {*} value - */ - if (func(value)) return [...ret, keepSplitedValue ? [value] : []] + const ret = [[]] + for (const value of arr) { + /** + * Return true at the split point. + * + * @callback splitCallback + * @param {*} value + */ + if (func(value)) { + ret.push(keepSplitedValue ? [value] : []) + } else { ret[ret.length - 1].push(value) - return ret - }, - [[]] - ) + } + } + + return ret } export default split diff --git a/src/helpers/wrap_tokens.js b/src/helpers/wrap_tokens.js index 5e31a2d2..3271afbe 100644 --- a/src/helpers/wrap_tokens.js +++ b/src/helpers/wrap_tokens.js @@ -18,9 +18,7 @@ function wrapTokens(type, container, tokens = []) { const { tag } = container // Update nesting level of wrapping tokens - tokens.forEach(t => { - t.level += 1 - }) + for (const t of tokens) t.level += 1 // Create markdown-it tokens const open = new Token(`${type}_open`, tag, 1) @@ -30,12 +28,10 @@ function wrapTokens(type, container, tokens = []) { Object.assign(close, { ...(container.close || {}) }) // Assign attributes - Object.keys(container).forEach(attr => { - if (['open', 'close', 'tag'].includes(attr)) return - if (container[attr] == null) return - - open.attrSet(attr, container[attr]) - }) + for (const attr of Object.keys(container)) { + if (!['open', 'close', 'tag'].includes(attr) && container[attr] != null) + open.attrSet(attr, container[attr]) + } return [open, ...tokens, close] } diff --git a/src/markdown/background_image.js b/src/markdown/background_image.js index 954d437f..e6d17b87 100644 --- a/src/markdown/background_image.js +++ b/src/markdown/background_image.js @@ -30,22 +30,20 @@ function backgroundImage(md) { 'marpit_parse_image', 'marpit_background_image', ({ tokens }) => { - tokens.forEach(t => { - if (t.type !== 'image') return - - if (t.meta.marpitImage.options.includes('bg')) { + for (const t of tokens) { + if (t.type === 'image' && t.meta.marpitImage.options.includes('bg')) { t.meta.marpitImage.background = true t.hidden = true - t.meta.marpitImage.options.forEach(opt => { + for (const opt of t.meta.marpitImage.options) { if (bgSizeKeywords[opt]) t.meta.marpitImage.backgroundSize = bgSizeKeywords[opt] if (opt === 'left' || opt === 'right') t.meta.marpitImage.backgroundSplit = opt - }) + } } - }) + } } ) @@ -57,7 +55,7 @@ function backgroundImage(md) { let current = {} - tokens.forEach(tb => { + for (const tb of tokens) { if (tb.type === 'marpit_slide_open') current.open = tb if (tb.type === 'marpit_inline_svg_content_open') current.svgContent = tb @@ -92,44 +90,44 @@ function backgroundImage(md) { current = {} } - if (!current.open || tb.type !== 'inline') return - - tb.children.forEach(t => { - if (t.type !== 'image') return - - const { - background, - backgroundSize, - backgroundSplit, - filter, - height, - size, - url, - width, - } = t.meta.marpitImage - - if (background && !url.match(/^\s*$/)) { - current.images = [ - ...(current.images || []), - { + if (current.open && tb.type === 'inline') + for (const t of tb.children) { + if (t.type === 'image') { + const { + background, + backgroundSize, + backgroundSplit, filter, height, - size: (() => { - const s = size || backgroundSize || undefined - - return !['contain', 'cover'].includes(s) && (width || height) - ? `${width || s || 'auto'} ${height || s || 'auto'}` - : s - })(), + size, url, width, - }, - ] - } + } = t.meta.marpitImage - if (backgroundSplit) current.split = backgroundSplit - }) - }) + if (background && !url.match(/^\s*$/)) { + current.images = [ + ...(current.images || []), + { + filter, + height, + size: (() => { + const s = size || backgroundSize || undefined + + return !['contain', 'cover'].includes(s) && + (width || height) + ? `${width || s || 'auto'} ${height || s || 'auto'}` + : s + })(), + url, + width, + }, + ] + } + + if (backgroundSplit) current.split = backgroundSplit + } + } + } } ) @@ -138,10 +136,9 @@ function backgroundImage(md) { 'marpit_advanced_background', state => { let current + const newTokens = [] - state.tokens = state.tokens.reduce((ret, t) => { - let tokens = [t] - + for (const t of state.tokens) { if ( t.type === 'marpit_inline_svg_content_open' && t.meta && @@ -160,7 +157,7 @@ function backgroundImage(md) { if (splitSide === 'left') t.attrSet('x', '50%') } - tokens = [ + newTokens.push( ...wrapTokens( 'marpit_advanced_background_foreign_object', { tag: 'foreignObject', width, height }, @@ -178,27 +175,30 @@ function backgroundImage(md) { tag: 'div', 'data-marpit-advanced-background-container': true, }, - images.reduce( - (imgArr, img) => [ - ...imgArr, - ...wrapTokens('marpit_advanced_background_image', { - tag: 'figure', - style: [ - `background-image:url("${img.url}");`, - img.size && `background-size:${img.size};`, - img.filter && `filter:${img.filter};`, - ] - .filter(s => s) - .join(''), - }), - ], - [] - ) + (() => { + const imageTokens = [] + + for (const img of images) + imageTokens.push( + ...wrapTokens('marpit_advanced_background_image', { + tag: 'figure', + style: [ + `background-image:url("${img.url}");`, + img.size && `background-size:${img.size};`, + img.filter && `filter:${img.filter};`, + ] + .filter(s => s) + .join(''), + }) + ) + + return imageTokens + })() ) ) ), - t, - ] + t + ) } else if (current && t.type === 'marpit_inline_svg_content_close') { const { open, height, width } = current.meta.marpitBackground @@ -212,7 +212,7 @@ function backgroundImage(md) { ) style.set('color', open.meta.marpitDirectives.color) - tokens = [ + newTokens.push( t, ...wrapTokens( 'marpit_advanced_background_foreign_object', @@ -231,14 +231,16 @@ function backgroundImage(md) { 'data-marpit-pagination' ), }) - ), - ] + ) + ) current = undefined + } else { + newTokens.push(t) } + } - return [...ret, ...tokens] - }, []) + state.tokens = newTokens } ) } diff --git a/src/markdown/container.js b/src/markdown/container.js index 4b4e9937..66c45cad 100644 --- a/src/markdown/container.js +++ b/src/markdown/container.js @@ -16,9 +16,8 @@ function container(md, containers) { md.core.ruler.push('marpit_containers', state => { if (state.inlineMode) return - target.forEach(cont => { + for (const cont of target) state.tokens = wrapTokens('marpit_containers', cont, state.tokens) - }) }) } diff --git a/src/markdown/directives/apply.js b/src/markdown/directives/apply.js index 31105a42..85c0bff2 100644 --- a/src/markdown/directives/apply.js +++ b/src/markdown/directives/apply.js @@ -32,66 +32,68 @@ function apply(md, opts = {}) { state => { if (state.inlineMode) return - state.tokens.forEach(token => { + for (const token of state.tokens) { const { marpitDirectives, marpitSlide } = token.meta || {} - if (!marpitDirectives) return - - const style = new InlineStyle(token.attrGet('style')) - - Object.keys(marpitDirectives) - .filter(filterFunc) - .forEach(dir => { - const value = marpitDirectives[dir] - if (!value) return - - const kebabCaseDir = kebabCase(dir) - if (dataset) token.attrSet(`data-${kebabCaseDir}`, value) - if (css) style.set(`--${kebabCaseDir}`, value) - }) - - // Apply attribute to token - if (marpitDirectives.class) - token.attrJoin('class', marpitDirectives.class) - - if (marpitDirectives.color) style.set('color', marpitDirectives.color) - - if (marpitDirectives.backgroundColor) - style - .set('background-color', marpitDirectives.backgroundColor) - .set('background-image', 'none') - - if (marpitDirectives.backgroundImage) { - style - .set('background-image', marpitDirectives.backgroundImage) - .set('background-position', 'center') - .set('background-repeat', 'no-repeat') - .set('background-size', 'cover') - - if (marpitDirectives.backgroundPosition) - style.set( - 'background-position', - marpitDirectives.backgroundPosition - ) - - if (marpitDirectives.backgroundRepeat) - style.set('background-repeat', marpitDirectives.backgroundRepeat) - - if (marpitDirectives.backgroundSize) - style.set('background-size', marpitDirectives.backgroundSize) - } - if (marpitDirectives.paginate) - token.attrSet('data-marpit-pagination', marpitSlide + 1) + if (marpitDirectives) { + const style = new InlineStyle(token.attrGet('style')) + + for (const dir of Object.keys(marpitDirectives)) { + if (filterFunc(dir)) { + const value = marpitDirectives[dir] + + if (value) { + const kebabCaseDir = kebabCase(dir) + if (dataset) token.attrSet(`data-${kebabCaseDir}`, value) + if (css) style.set(`--${kebabCaseDir}`, value) + } + } + } + + // Apply attribute to token + if (marpitDirectives.class) + token.attrJoin('class', marpitDirectives.class) + + if (marpitDirectives.color) style.set('color', marpitDirectives.color) + + if (marpitDirectives.backgroundColor) + style + .set('background-color', marpitDirectives.backgroundColor) + .set('background-image', 'none') - if (marpitDirectives.header) - token.meta.marpitHeader = marpitDirectives.header + if (marpitDirectives.backgroundImage) { + style + .set('background-image', marpitDirectives.backgroundImage) + .set('background-position', 'center') + .set('background-repeat', 'no-repeat') + .set('background-size', 'cover') - if (marpitDirectives.footer) - token.meta.marpitFooter = marpitDirectives.footer + if (marpitDirectives.backgroundPosition) + style.set( + 'background-position', + marpitDirectives.backgroundPosition + ) - const styleStr = style.toString() - if (styleStr !== '') token.attrSet('style', styleStr) - }) + if (marpitDirectives.backgroundRepeat) + style.set('background-repeat', marpitDirectives.backgroundRepeat) + + if (marpitDirectives.backgroundSize) + style.set('background-size', marpitDirectives.backgroundSize) + } + + if (marpitDirectives.paginate) + token.attrSet('data-marpit-pagination', marpitSlide + 1) + + if (marpitDirectives.header) + token.meta.marpitHeader = marpitDirectives.header + + if (marpitDirectives.footer) + token.meta.marpitFooter = marpitDirectives.footer + + const styleStr = style.toString() + if (styleStr !== '') token.attrSet('style', styleStr) + } + } } ) } diff --git a/src/markdown/directives/parse.js b/src/markdown/directives/parse.js index bf142ddb..6362ee91 100644 --- a/src/markdown/directives/parse.js +++ b/src/markdown/directives/parse.js @@ -45,7 +45,7 @@ function parse(md, marpit, opts = {}) { let globalDirectives = {} const applyDirectives = obj => { - Object.keys(obj).forEach(key => { + for (const key of Object.keys(obj)) { const globalKey = key.startsWith('$') ? key.slice(1) : key if (globals[globalKey]) @@ -53,20 +53,20 @@ function parse(md, marpit, opts = {}) { ...globalDirectives, ...globals[globalKey](obj[key], marpit), } - }) + } } if (frontMatterObject.yaml) applyDirectives(frontMatterObject.yaml) - state.tokens.forEach(token => { + for (const token of state.tokens) { if (isComment(token)) { applyDirectives(token.meta.marpitParsedDirectives) } else if (token.type === 'inline') { - token.children - .filter(isComment) - .forEach(t => applyDirectives(t.meta.marpitParsedDirectives)) + for (const t of token.children) { + if (isComment(t)) applyDirectives(t.meta.marpitParsedDirectives) + } } - }) + } marpit.lastGlobalDirectives = { ...globalDirectives } }) @@ -79,7 +79,7 @@ function parse(md, marpit, opts = {}) { const cursor = { slide: undefined, local: {}, spot: {} } const applyDirectives = obj => { - Object.keys(obj).forEach(key => { + for (const key of Object.keys(obj)) { if (locals[key]) cursor.local = { ...cursor.local, ...locals[key](obj[key], marpit) } @@ -94,12 +94,12 @@ function parse(md, marpit, opts = {}) { ...locals[spotKey](obj[key], marpit), } } - }) + } } if (frontMatterObject.yaml) applyDirectives(frontMatterObject.yaml) - state.tokens.forEach(token => { + for (const token of state.tokens) { if (token.meta && token.meta.marpitSlideElement === 1) { // Initialize Marpit directives meta token.meta.marpitDirectives = {} @@ -118,19 +118,18 @@ function parse(md, marpit, opts = {}) { } else if (isComment(token)) { applyDirectives(token.meta.marpitParsedDirectives) } else if (token.type === 'inline') { - token.children - .filter(isComment) - .forEach(t => applyDirectives(t.meta.marpitParsedDirectives)) + for (const t of token.children) { + if (isComment(t)) applyDirectives(t.meta.marpitParsedDirectives) + } } - }) + } // Assign global directives to meta - slides.forEach(token => { + for (const token of slides) token.meta.marpitDirectives = { ...token.meta.marpitDirectives, ...marpit.lastGlobalDirectives, } - }) }) } diff --git a/src/markdown/directives/yaml.js b/src/markdown/directives/yaml.js index a02ceff0..b50557b8 100644 --- a/src/markdown/directives/yaml.js +++ b/src/markdown/directives/yaml.js @@ -28,24 +28,22 @@ function parse(text) { } function convertLoose(text) { - return text - .split(/\r?\n/) - .reduce( - (ret, line) => - `${ret}${line.replace(looseMatcher, (original, prop, value) => { - const trimmed = value.trim() - - if (trimmed.length === 0 || specialChars.includes(trimmed[0])) - return original - - const spaceLength = value.length - value.trimLeft().length - const spaces = value.substring(0, spaceLength) - - return `${prop}${spaces}"${trimmed.split('"').join('\\"')}"` - })}\n`, - '' - ) - .trim() + let normalized = '' + + for (const line of text.split(/\r?\n/)) + normalized += `${line.replace(looseMatcher, (original, prop, value) => { + const trimmed = value.trim() + + if (trimmed.length === 0 || specialChars.includes(trimmed[0])) + return original + + const spaceLength = value.length - value.trimLeft().length + const spaces = value.substring(0, spaceLength) + + return `${prop}${spaces}"${trimmed.split('"').join('\\"')}"` + })}\n` + + return normalized.trim() } export default (text, allowLoose) => diff --git a/src/markdown/header_and_footer.js b/src/markdown/header_and_footer.js index dc03bc63..7b38549a 100644 --- a/src/markdown/header_and_footer.js +++ b/src/markdown/header_and_footer.js @@ -38,28 +38,30 @@ function headerAndFooter(md) { ) let current + const newTokens = [] - state.tokens = state.tokens.reduce((arr, token) => { - let concats = [token] - + for (const token of state.tokens) { if (token.type === 'marpit_slide_open') { current = token + newTokens.push(token) if (current.meta && current.meta.marpitHeader) - concats = [ - ...concats, - ...createMarginalTokens('header', current.meta.marpitHeader), - ] + newTokens.push( + ...createMarginalTokens('header', current.meta.marpitHeader) + ) } else if (token.type === 'marpit_slide_close') { if (current.meta && current.meta.marpitFooter) - concats = [ - ...createMarginalTokens('footer', current.meta.marpitFooter), - ...concats, - ] + newTokens.push( + ...createMarginalTokens('footer', current.meta.marpitFooter) + ) + + newTokens.push(token) + } else { + newTokens.push(token) } + } - return [...arr, ...concats] - }, []) + state.tokens = newTokens } ) } diff --git a/src/markdown/heading_divider.js b/src/markdown/heading_divider.js index 0ea1ef63..41e80b60 100644 --- a/src/markdown/heading_divider.js +++ b/src/markdown/heading_divider.js @@ -34,24 +34,22 @@ function headingDivider(md, marpit) { const splitTag = target.map(i => `h${i}`) const splitFunc = t => t.type === 'heading_open' && splitTag.includes(t.tag) + const newTokens = [] - state.tokens = split(state.tokens, splitFunc, true).reduce( - (arr, slideTokens) => { - const [firstToken] = slideTokens + for (const slideTokens of split(state.tokens, splitFunc, true)) { + const [token] = slideTokens - if ( - !(firstToken && splitFunc(firstToken)) || - arr.filter(t => !t.hidden).length === 0 - ) - return [...arr, ...slideTokens] + if (token && splitFunc(token) && newTokens.some(t => !t.hidden)) { + const hr = new Token('hr', '', 0) + hr.hidden = true - const token = new Token('hr', '', 0) - token.hidden = true + newTokens.push(hr) + } - return [...arr, token, ...slideTokens] - }, - [] - ) + newTokens.push(...slideTokens) + } + + state.tokens = newTokens }) } diff --git a/src/markdown/inline_svg.js b/src/markdown/inline_svg.js index 7c03aa77..a070d771 100644 --- a/src/markdown/inline_svg.js +++ b/src/markdown/inline_svg.js @@ -16,37 +16,38 @@ function inlineSVG(md, marpit) { const { themeSet, lastGlobalDirectives } = marpit const w = themeSet.getThemeProp(lastGlobalDirectives.theme, 'widthPixel') const h = themeSet.getThemeProp(lastGlobalDirectives.theme, 'heightPixel') + const newTokens = [] - state.tokens = split( + for (const tokens of split( state.tokens, t => t.meta && t.meta.marpitSlideElement === 1, true - ).reduce((arr, tokens) => { - if (tokens.length === 0) return arr + )) { + if (tokens.length > 0) { + for (const t of tokens) + if (t.meta && t.meta.marpitSlideElement) + delete t.meta.marpitSlideElement - tokens.forEach(t => { - if (t.meta && t.meta.marpitSlideElement) - delete t.meta.marpitSlideElement - }) - - return [ - ...arr, - ...wrapTokens( - 'marpit_inline_svg', - { - tag: 'svg', - viewBox: `0 0 ${w} ${h}`, - open: { meta: { marpitSlideElement: 1 } }, - close: { meta: { marpitSlideElement: -1 } }, - }, - wrapTokens( - 'marpit_inline_svg_content', - { tag: 'foreignObject', width: w, height: h }, - tokens + newTokens.push( + ...wrapTokens( + 'marpit_inline_svg', + { + tag: 'svg', + viewBox: `0 0 ${w} ${h}`, + open: { meta: { marpitSlideElement: 1 } }, + close: { meta: { marpitSlideElement: -1 } }, + }, + wrapTokens( + 'marpit_inline_svg_content', + { tag: 'foreignObject', width: w, height: h }, + tokens + ) ) - ), - ] - }, []) + ) + } + } + + state.tokens = newTokens }) } diff --git a/src/markdown/parse_image.js b/src/markdown/parse_image.js index e6bd1f9f..49f769db 100644 --- a/src/markdown/parse_image.js +++ b/src/markdown/parse_image.js @@ -51,16 +51,19 @@ function parseImage(md, opts = {}) { optionMatchers.set( /^drop-shadow(?::(.+?),(.+?)(?:,(.+?))?(?:,(.+?))?)?$/, (matches, meta) => { - const args = matches - .slice(1) - .filter(v => v) - .map(arg => { + const args = [] + + for (const arg of matches.slice(1)) { + if (arg) { const colorFunc = arg.match(/^(rgba?|hsla?)\((.*)\)$/) - return colorFunc - ? `${colorFunc[1]}(${escape(colorFunc[2])})` - : escape(arg) - }) + args.push( + colorFunc + ? `${colorFunc[1]}(${escape(colorFunc[2])})` + : escape(arg) + ) + } + } return { filters: [ @@ -94,7 +97,7 @@ function parseImage(md, opts = {}) { } md.inline.ruler2.push('marpit_parse_image', ({ tokens }) => { - tokens.forEach(token => { + for (const token of tokens) { if (token.type === 'image') { const options = token.content.split(/\s+/).filter(s => s.length > 0) @@ -105,8 +108,8 @@ function parseImage(md, opts = {}) { options, } - options.forEach(opt => { - optionMatchers.forEach((mergeFunc, regexp) => { + for (const opt of options) + for (const [regexp, mergeFunc] of optionMatchers) { const matched = opt.match(regexp) if (matched) @@ -117,8 +120,7 @@ function parseImage(md, opts = {}) { ...token.meta.marpitImage, }), } - }) - }) + } // Build and apply styles const { filters, height, width } = token.meta.marpitImage @@ -135,17 +137,19 @@ function parseImage(md, opts = {}) { if (height) assign('height', height) if (filters) { - token.meta.marpitImage.filter = filters - .reduce((arr, fltrs) => [...arr, `${fltrs[0]}(${fltrs[1]})`], []) - .join(' ') + const filterStyle = [] + + for (const fltrs of filters) + filterStyle.push(`${fltrs[0]}(${fltrs[1]})`) + token.meta.marpitImage.filter = filterStyle.join(' ') style.set('filter', token.meta.marpitImage.filter) } const stringified = style.toString() if (stringified) token.attrSet('style', stringified) } - }) + } }) } diff --git a/src/markdown/slide_container.js b/src/markdown/slide_container.js index 20798d09..0108a675 100644 --- a/src/markdown/slide_container.js +++ b/src/markdown/slide_container.js @@ -17,22 +17,24 @@ function slideContainer(md, containers) { md.core.ruler.push('marpit_slide_containers', state => { if (state.inlineMode) return - state.tokens = split( + const newTokens = [] + + for (const tokens of split( state.tokens, t => t.meta && t.meta.marpitSlideElement === 1, true - ).reduce((arr, tokens) => { - if (tokens.length === 0) return arr + )) { + if (tokens.length > 0) + newTokens.push( + ...target.reduce( + (slides, conts) => + wrapTokens('marpit_slide_containers', conts, slides), + tokens + ) + ) + } - return [ - ...arr, - ...target.reduce( - (slides, conts) => - wrapTokens('marpit_slide_containers', conts, slides), - tokens - ), - ] - }, []) + state.tokens = newTokens }) } diff --git a/src/markdown/style/assign.js b/src/markdown/style/assign.js index 01b17248..88a41661 100644 --- a/src/markdown/style/assign.js +++ b/src/markdown/style/assign.js @@ -17,9 +17,8 @@ function assign(md, marpit) { const directives = marpit.lastGlobalDirectives || {} marpit.lastStyles = directives.style ? [directives.style] : [] - state.tokens.forEach(token => { + for (const token of state.tokens) if (token.type === 'marpit_style') marpit.lastStyles.push(token.content) - }) }) } diff --git a/src/markdown/sweep.js b/src/markdown/sweep.js index e7ae6bd5..6c905f31 100644 --- a/src/markdown/sweep.js +++ b/src/markdown/sweep.js @@ -14,7 +14,7 @@ function sweep(md) { md.core.ruler.after('inline', 'marpit_sweep', state => { if (state.inlineMode) return - state.tokens.forEach(token => { + for (const token of state.tokens) { if ( (token.type === 'html_block' && token.content.match(/^\s*$/)) || (token.type === 'inline' && @@ -23,14 +23,14 @@ function sweep(md) { .every(t => t.type === 'text' && t.content.match(/^\s*$/))) ) token.hidden = true - }) + } }) md.core.ruler.push('marpit_sweep_paragraph', state => { if (state.inlineMode) return const current = { open: [], tokens: {} } - state.tokens.forEach(token => { + for (const token of state.tokens) { if (token.type === 'paragraph_open') { current.open.push(token) current.tokens[token] = [] @@ -45,7 +45,7 @@ function sweep(md) { const len = current.open.length if (len > 0) current.tokens[current.open[len - 1]].push(token) } - }) + } }) } diff --git a/src/postcss/import/replace.js b/src/postcss/import/replace.js index 24d3a90b..1c451c7c 100644 --- a/src/postcss/import/replace.js +++ b/src/postcss/import/replace.js @@ -39,14 +39,13 @@ const plugin = postcss.plugin( node.replaceWith(processed.root) } else { node.remove() - prepends.push(processed.root) + prepends.unshift(processed.root) } } } }) - if (prepends.length > 0) - [...prepends].reverse().forEach(root => css.first.before(root)) + for (const root of prepends) css.first.before(root) }, ]) )