Skip to content

Commit 16f07a6

Browse files
committed
add pre & post css transform callbacks to customize css transformation behavior
1 parent 34dd1e6 commit 16f07a6

File tree

4 files changed

+88
-33
lines changed

4 files changed

+88
-33
lines changed

lib/compilers/helpers/module-name-mapper-helper.js

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
const path = require('path')
2-
2+
const matchModuleImport = /^[^?]*~/
33
/**
44
* Resolves the path to the file locally.
55
*
66
* @param {String} to - the name of the file to resolve to
7-
* @param {String} localPath - the local path
7+
* @param {String} importPath - the local path
8+
* @param {String} fileType - extn of the file to be resolved
89
* @returns {String} path - path to the file to import
910
*/
10-
function localResolve(to, localPath) {
11-
if (localPath.startsWith('/')) {
12-
return localPath
11+
function resolve(to, importPath, fileType) {
12+
importPath =
13+
path.extname(importPath) === '' ? `${importPath}.${fileType}` : importPath
14+
if (importPath.startsWith('/')) {
15+
return importPath
16+
} else if (matchModuleImport.test(importPath)) {
17+
return require.resolve(importPath.replace(matchModuleImport, ''))
1318
}
14-
return path.join(path.dirname(to), localPath)
19+
return path.join(path.dirname(to), importPath)
1520
}
1621

1722
/**
@@ -20,12 +25,14 @@ function localResolve(to, localPath) {
2025
* @param {String} source - the original string
2126
* @param {String} filePath - the path of the current file (where the source originates)
2227
* @param {Object} jestConfig - the jestConfig holding the moduleNameMapper settings
28+
* @param {Object} fileType - extn of the file to be resolved
2329
* @returns {String} path - the final path to import (including replacements via moduleNameMapper)
2430
*/
2531
module.exports = function applyModuleNameMapper(
2632
source,
2733
filePath,
28-
jestConfig = {}
34+
jestConfig = {},
35+
fileType = ''
2936
) {
3037
if (!jestConfig.moduleNameMapper) return source
3138

@@ -47,5 +54,5 @@ module.exports = function applyModuleNameMapper(
4754
)
4855
}, source)
4956

50-
return localResolve(filePath, importPath)
57+
return resolve(filePath, importPath, fileType)
5158
}

lib/compilers/sass-compiler.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ module.exports = (content, filePath, jestConfig = {}) => {
2828
file: applyModuleNameMapper(
2929
url,
3030
prev === 'stdin' ? filePath : prev,
31-
jestConfig
31+
jestConfig,
32+
'sass'
3233
)
3334
})
3435
})

lib/compilers/scss-compiler.js

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
const path = require('path')
2-
const fs = require('fs')
31
const ensureRequire = require('../ensure-require')
42
const getVueJestConfig = require('../utils').getVueJestConfig
53
const warn = require('../utils').warn
@@ -19,26 +17,17 @@ module.exports = (content, filePath, jestConfig = {}) => {
1917

2018
ensureRequire('scss', ['node-sass'])
2119
const sass = require('node-sass')
22-
23-
let scssResources = ''
24-
if (vueJestConfig.resources && vueJestConfig.resources.scss) {
25-
scssResources = vueJestConfig.resources.scss
26-
.map(scssResource => path.resolve(process.cwd(), scssResource))
27-
.filter(scssResourcePath => fs.existsSync(scssResourcePath))
28-
.map(scssResourcePath => fs.readFileSync(scssResourcePath).toString())
29-
.join('\n')
30-
}
31-
3220
try {
3321
return sass
3422
.renderSync({
35-
data: scssResources + content,
23+
data: content,
3624
outputStyle: 'compressed',
3725
importer: (url, prev, done) => ({
3826
file: applyModuleNameMapper(
3927
url,
4028
prev === 'stdin' ? filePath : prev,
41-
jestConfig
29+
jestConfig,
30+
'scss'
4231
)
4332
})
4433
})

lib/process-style.js

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,73 @@
1+
const path = require('path')
2+
const fs = require('fs')
13
const getVueJestConfig = require('./utils').getVueJestConfig
4+
const warn = require('./utils').warn
25
const cssExtract = require('extract-from-css')
36

47
module.exports = function processStyle(stylePart, filePath, jestConfig = {}) {
58
const vueJestConfig = getVueJestConfig(jestConfig)
9+
let cssTransform =
10+
vueJestConfig['cssTransform'] &&
11+
vueJestConfig['cssTransform'][stylePart.lang]
12+
if (cssTransform && /^less|pcss|postcss/.test(stylePart.lang)) {
13+
!vueJestConfig.hideStyleWarn &&
14+
warn(
15+
'Less and PostCSS transforms are not currently supported by vue-jest'
16+
)
17+
}
18+
const validTransforms =
19+
cssTransform &&
20+
!/^less|pcss|postcss/.test(stylePart.lang) &&
21+
(cssTransform.pre || cssTransform.post)
22+
cssTransform = cssTransform || {}
623

724
if (!stylePart || vueJestConfig.experimentalCSSCompile === false) {
825
return {}
926
}
1027

11-
const processStyleByLang = lang =>
12-
require('./compilers/' + lang + '-compiler')(
13-
stylePart.content,
28+
const globaResources = lang => {
29+
let globalResources = ''
30+
if (vueJestConfig.resources && vueJestConfig.resources[lang]) {
31+
globalResources = vueJestConfig.resources[lang]
32+
.map(resource => path.resolve(process.cwd(), resource))
33+
.filter(resourcePath => fs.existsSync(resourcePath))
34+
.map(resourcePath => fs.readFileSync(resourcePath).toString())
35+
.join('\n')
36+
}
37+
return globalResources
38+
}
39+
40+
const cssTransfomer = (transform, content) => {
41+
if (!validTransforms || !transform || typeof transform !== 'string') {
42+
return content
43+
}
44+
45+
return require(path.resolve(process.cwd(), transform))(
46+
content,
47+
vueJestConfig,
48+
stylePart.attrs
49+
)
50+
}
51+
52+
const processStyleByLang = lang => {
53+
const content = globaResources(lang) + stylePart.content
54+
const preProcessedContent = cssTransfomer(cssTransform.pre, content)
55+
return require('./compilers/' + lang + '-compiler')(
56+
preProcessedContent,
1457
filePath,
1558
jestConfig
1659
)
60+
}
61+
62+
const extractClassMap = cssCode => {
63+
const cssNames = cssExtract.extractClasses(cssCode)
64+
const obj = {}
65+
for (let i = 0, l = cssNames.length; i < l; i++) {
66+
obj[cssNames[i]] = cssNames[i]
67+
}
68+
69+
return obj
70+
}
1771

1872
let cssCode = stylePart.content
1973
switch (stylePart.lang) {
@@ -29,12 +83,16 @@ module.exports = function processStyle(stylePart, filePath, jestConfig = {}) {
2983
break
3084
}
3185

32-
const cssNames = cssExtract.extractClasses(cssCode)
33-
34-
const obj = {}
35-
for (let i = 0, l = cssNames.length; i < l; i++) {
36-
obj[cssNames[i]] = cssNames[i]
86+
if (validTransforms) {
87+
const locals = cssTransfomer(cssTransform.post, cssCode)
88+
if (typeof locals !== 'object') {
89+
!vueJestConfig.hideStyleWarn &&
90+
warn(
91+
'post-transformers are expected to return an object with key value pair as class names of the component'
92+
)
93+
}
94+
return locals
95+
} else {
96+
return extractClassMap(cssCode)
3797
}
38-
39-
return obj
4098
}

0 commit comments

Comments
 (0)