From 795f393dba2f14de59ccaa319dc3ac939f658304 Mon Sep 17 00:00:00 2001 From: Jakub Freisler <jakub@frsource.org> Date: Wed, 29 Dec 2021 15:38:03 +0100 Subject: [PATCH 1/3] feat: add postcss 8 support Signed-off-by: Jakub Freisler <jakub@frsource.org> --- lib/stylePlugins/scoped.ts | 175 +++++++++++++++++++------------------ lib/stylePlugins/trim.ts | 22 +++-- package.json | 2 +- test/compileStyle.spec.ts | 14 +-- yarn.lock | 31 ++++--- 5 files changed, 133 insertions(+), 111 deletions(-) diff --git a/lib/stylePlugins/scoped.ts b/lib/stylePlugins/scoped.ts index 14e1a2d..4c5bb89 100644 --- a/lib/stylePlugins/scoped.ts +++ b/lib/stylePlugins/scoped.ts @@ -1,101 +1,106 @@ -import { Root } from 'postcss' -import * as postcss from 'postcss' +import { Root, PluginCreator } from 'postcss' // postcss-selector-parser does have typings but it's problematic to work with. const selectorParser = require('postcss-selector-parser') -export default postcss.plugin('add-id', (options: any) => (root: Root) => { - const id: string = options - const keyframes = Object.create(null) +const pluginFn: PluginCreator<any> = options => ({ + postcssPlugin: 'add-id', + Once(root: Root) { + const id: string = options + const keyframes = Object.create(null) - root.each(function rewriteSelector(node: any) { - if (!node.selector) { - // handle media queries - if (node.type === 'atrule') { - if (node.name === 'media' || node.name === 'supports') { - node.each(rewriteSelector) - } else if (/-?keyframes$/.test(node.name)) { - // register keyframes - keyframes[node.params] = node.params = node.params + '-' + id + root.each(function rewriteSelector(node: any) { + if (!node.selector) { + // handle media queries + if (node.type === 'atrule') { + if (node.name === 'media' || node.name === 'supports') { + node.each(rewriteSelector) + } else if (/-?keyframes$/.test(node.name)) { + // register keyframes + keyframes[node.params] = node.params = node.params + '-' + id + } } + return } - return - } - node.selector = selectorParser((selectors: any) => { - selectors.each((selector: any) => { - let node: any = null + node.selector = selectorParser((selectors: any) => { + selectors.each((selector: any) => { + let node: any = null - // find the last child node to insert attribute selector - selector.each((n: any) => { - // ">>>" combinator - // and /deep/ alias for >>>, since >>> doesn't work in SASS - if ( - n.type === 'combinator' && - (n.value === '>>>' || n.value === '/deep/') - ) { - n.value = ' ' - n.spaces.before = n.spaces.after = '' - return false - } + // find the last child node to insert attribute selector + selector.each((n: any) => { + // ">>>" combinator + // and /deep/ alias for >>>, since >>> doesn't work in SASS + if ( + n.type === 'combinator' && + (n.value === '>>>' || n.value === '/deep/') + ) { + n.value = ' ' + n.spaces.before = n.spaces.after = '' + return false + } - // in newer versions of sass, /deep/ support is also dropped, so add a ::v-deep alias - if (n.type === 'pseudo' && n.value === '::v-deep') { - n.value = n.spaces.before = n.spaces.after = '' - return false - } + // in newer versions of sass, /deep/ support is also dropped, so add a ::v-deep alias + if (n.type === 'pseudo' && n.value === '::v-deep') { + n.value = n.spaces.before = n.spaces.after = '' + return false + } - if (n.type !== 'pseudo' && n.type !== 'combinator') { - node = n + if (n.type !== 'pseudo' && n.type !== 'combinator') { + node = n + } + }) + + if (node) { + node.spaces.after = '' + } else { + // For deep selectors & standalone pseudo selectors, + // the attribute selectors are prepended rather than appended. + // So all leading spaces must be eliminated to avoid problems. + selector.first.spaces.before = '' } + + selector.insertAfter( + node, + selectorParser.attribute({ + attribute: id + }) + ) }) + }).processSync(node.selector) + }) - if (node) { - node.spaces.after = '' - } else { - // For deep selectors & standalone pseudo selectors, - // the attribute selectors are prepended rather than appended. - // So all leading spaces must be eliminated to avoid problems. - selector.first.spaces.before = '' + // If keyframes are found in this <style>, find and rewrite animation names + // in declarations. + // Caveat: this only works for keyframes and animation rules in the same + // <style> element. + if (Object.keys(keyframes).length) { + root.walkDecls(decl => { + // individual animation-name declaration + if (/^(-\w+-)?animation-name$/.test(decl.prop)) { + decl.value = decl.value + .split(',') + .map(v => keyframes[v.trim()] || v.trim()) + .join(',') + } + // shorthand + if (/^(-\w+-)?animation$/.test(decl.prop)) { + decl.value = decl.value + .split(',') + .map(v => { + const vals = v.trim().split(/\s+/) + const i = vals.findIndex(val => keyframes[val]) + if (i !== -1) { + vals.splice(i, 1, keyframes[vals[i]]) + return vals.join(' ') + } else { + return v + } + }) + .join(',') } - - selector.insertAfter( - node, - selectorParser.attribute({ - attribute: id - }) - ) }) - }).processSync(node.selector) - }) - - // If keyframes are found in this <style>, find and rewrite animation names - // in declarations. - // Caveat: this only works for keyframes and animation rules in the same - // <style> element. - if (Object.keys(keyframes).length) { - root.walkDecls(decl => { - // individual animation-name declaration - if (/^(-\w+-)?animation-name$/.test(decl.prop)) { - decl.value = decl.value - .split(',') - .map(v => keyframes[v.trim()] || v.trim()) - .join(',') - } - // shorthand - if (/^(-\w+-)?animation$/.test(decl.prop)) { - decl.value = decl.value - .split(',') - .map(v => { - const vals = v.trim().split(/\s+/) - const i = vals.findIndex(val => keyframes[val]) - if (i !== -1) { - vals.splice(i, 1, keyframes[vals[i]]) - return vals.join(' ') - } else { - return v - } - }) - .join(',') - } - }) + } } }) + +pluginFn.postcss = true +export default pluginFn diff --git a/lib/stylePlugins/trim.ts b/lib/stylePlugins/trim.ts index e4aed6a..2cfcbf0 100644 --- a/lib/stylePlugins/trim.ts +++ b/lib/stylePlugins/trim.ts @@ -1,11 +1,15 @@ -import { Root } from 'postcss' -import * as postcss from 'postcss' +import { PluginCreator, Rule, AtRule } from 'postcss' -export default postcss.plugin('trim', () => (css: Root) => { - css.walk(({ type, raws }) => { - if (type === 'rule' || type === 'atrule') { - if (raws.before) raws.before = '\n' - if (raws.after) raws.after = '\n' - } - }) +const trim = function({ raws }: Rule | AtRule) { + if (raws.before) raws.before = '\n' + if (raws.after) raws.after = '\n' +} + +const pluginFn: PluginCreator<void> = () => ({ + postcssPlugin: 'trim', + AtRule: trim, + Rule: trim }) + +pluginFn.postcss = true +export default pluginFn diff --git a/package.json b/package.json index 69e4faa..5bcb270 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "hash-sum": "^1.0.2", "lru-cache": "^4.1.2", "merge-source-map": "^1.1.0", - "postcss": "^7.0.36", + "postcss": "^8.0.0", "postcss-selector-parser": "^6.0.2", "source-map": "~0.6.1", "vue-template-es2015-compiler": "^1.9.0" diff --git a/test/compileStyle.spec.ts b/test/compileStyle.spec.ts index 58f059a..82fc693 100644 --- a/test/compileStyle.spec.ts +++ b/test/compileStyle.spec.ts @@ -138,9 +138,10 @@ test('async postcss plugin in sync mode', () => { source: '.foo { color: red }', scoped: false, postcssPlugins: [ - require('postcss').plugin('test-plugin', () => async (result: any) => - result - ) + { + postcssPlugin: 'test-plugin', + Once: async (result: any) => result + } ] }) @@ -154,9 +155,10 @@ test('async postcss plugin', async () => { source: '.foo { color: red }', scoped: false, postcssPlugins: [ - require('postcss').plugin('test-plugin', () => async (result: any) => - result - ) + { + postcssPlugin: 'test-plugin', + Once: async (result: any) => result + } ] }) diff --git a/yarn.lock b/yarn.lock index 919f2b3..8bdbc10 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3579,6 +3579,11 @@ nan@^2.12.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== +nanoid@^3.1.30: + version "3.1.30" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" + integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -3954,10 +3959,10 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -picocolors@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" - integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== picomatch@^2.0.4, picomatch@^2.2.1: version "2.2.2" @@ -4031,13 +4036,14 @@ postcss-selector-parser@^6.0.2: indexes-of "^1.0.1" uniq "^1.0.1" -postcss@^7.0.36: - version "7.0.39" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" - integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== +postcss@^8.0.0: + version "8.4.5" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" + integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== dependencies: - picocolors "^0.2.1" - source-map "^0.6.1" + nanoid "^3.1.30" + picocolors "^1.0.0" + source-map-js "^1.0.1" prelude-ls@~1.1.2: version "1.1.2" @@ -4692,6 +4698,11 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" +source-map-js@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf" + integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA== + source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" From 18a0ce3ebbacc6b8b3571276eddf1e7388d363a7 Mon Sep 17 00:00:00 2001 From: Jakub Freisler <jakub@frsource.org> Date: Fri, 4 Feb 2022 16:43:29 +0100 Subject: [PATCH 2/3] chore: raise postcss version to 8.1.3 Signed-off-by: Jakub Freisler <jakub@frsource.org> --- package.json | 2 +- yarn.lock | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 5bcb270..e7c49ef 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "hash-sum": "^1.0.2", "lru-cache": "^4.1.2", "merge-source-map": "^1.1.0", - "postcss": "^8.0.0", + "postcss": "^8.4.6", "postcss-selector-parser": "^6.0.2", "source-map": "~0.6.1", "vue-template-es2015-compiler": "^1.9.0" diff --git a/yarn.lock b/yarn.lock index 8bdbc10..3db47bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3579,10 +3579,10 @@ nan@^2.12.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== -nanoid@^3.1.30: - version "3.1.30" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" - integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ== +nanoid@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c" + integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA== nanomatch@^1.2.9: version "1.2.13" @@ -4036,14 +4036,14 @@ postcss-selector-parser@^6.0.2: indexes-of "^1.0.1" uniq "^1.0.1" -postcss@^8.0.0: - version "8.4.5" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" - integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== +postcss@^8.4.6: + version "8.4.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.6.tgz#c5ff3c3c457a23864f32cb45ac9b741498a09ae1" + integrity sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA== dependencies: - nanoid "^3.1.30" + nanoid "^3.2.0" picocolors "^1.0.0" - source-map-js "^1.0.1" + source-map-js "^1.0.2" prelude-ls@~1.1.2: version "1.1.2" @@ -4698,10 +4698,10 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -source-map-js@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf" - integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA== +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: version "0.5.3" From 5859be4b76199d715d0fa2011506800e62c03d92 Mon Sep 17 00:00:00 2001 From: Jakub Freisler <jakub@frsource.org> Date: Fri, 4 Feb 2022 16:46:40 +0100 Subject: [PATCH 3/3] feat: migrate test-plugin to new syntax Signed-off-by: Jakub Freisler <jakub@frsource.org> --- test/compileStyle.spec.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/compileStyle.spec.ts b/test/compileStyle.spec.ts index 82fc693..dafaab9 100644 --- a/test/compileStyle.spec.ts +++ b/test/compileStyle.spec.ts @@ -113,7 +113,12 @@ test('custom postcss plugin', () => { filename: 'example.vue', source: '.foo { color: red }', scoped: false, - postcssPlugins: [require('postcss').plugin('test-plugin', () => spy)()] + postcssPlugins: [ + { + postcssPlugin: 'test-plugin', + Once: spy + } + ] }) expect(spy).toHaveBeenCalled()