mirror of https://github.com/curbengh/hexo-yam
feat(globbing): support disabling basename for each pattern in 'include:' option
This commit is contained in:
parent
9d6b72422b
commit
50d80ccc70
20
README.md
20
README.md
|
@ -58,9 +58,25 @@ minify:
|
||||||
- **globOptions** - [micromatch options](https://github.com/micromatch/micromatch#options) to customise how glob patterns match files.
|
- **globOptions** - [micromatch options](https://github.com/micromatch/micromatch#options) to customise how glob patterns match files.
|
||||||
- Defaults to `{ basename: true }`, unless the pattern has a slash.
|
- Defaults to `{ basename: true }`, unless the pattern has a slash.
|
||||||
- basename is disabled depending on each pattern.
|
- basename is disabled depending on each pattern.
|
||||||
- When specifying an array of patterns, e.g. `exclude: ['*foo.html', '**/bar.html']`, basename applies to `'*foo.html'`, but not `'**/bar.html'`.
|
- This means the following options would work,
|
||||||
|
``` yml
|
||||||
|
exclude:
|
||||||
|
- '*foo.html'
|
||||||
|
- '**/bar/*/*.html'
|
||||||
|
globOptions:
|
||||||
|
basename: true # default
|
||||||
|
```
|
||||||
|
- This behaviour doesn't apply to pattern that starts with `!` (negation).
|
||||||
|
- This limitation only applies to `include:` option used in svg, gzip and brotli.
|
||||||
|
- This means the following options would *not* work,
|
||||||
|
``` yml
|
||||||
|
include:
|
||||||
|
- '!foo.svg'
|
||||||
|
- '!**/bar/*/*.svg'
|
||||||
|
globOptions:
|
||||||
|
basename: true
|
||||||
|
```
|
||||||
- basename would stay disabled, if explicitly disabled in `globOptions:`.
|
- basename would stay disabled, if explicitly disabled in `globOptions:`.
|
||||||
- However, basename option applies to all patterns in `include:`
|
|
||||||
|
|
||||||
For more options, see [HTMLMinifier](https://github.com/kangax/html-minifier).
|
For more options, see [HTMLMinifier](https://github.com/kangax/html-minifier).
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,30 @@ const isMatch = (path = '', patterns = [], options = {}) => {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const match = (paths = [], patterns = [], options = {}) => {
|
||||||
|
let input = paths
|
||||||
|
if (paths && patterns) {
|
||||||
|
if (paths.length && patterns.length) {
|
||||||
|
const output = []
|
||||||
|
if (typeof patterns === 'string') patterns = [patterns]
|
||||||
|
const exclude = patterns.filter((pattern) => pattern.startsWith('!'))
|
||||||
|
const include = patterns.filter((pattern) => !pattern.startsWith('!'))
|
||||||
|
if (exclude.length) input = micromatch(paths, exclude, options)
|
||||||
|
if (include.length) {
|
||||||
|
for (const pattern of include) {
|
||||||
|
let { basename } = options
|
||||||
|
basename = basename && !pattern.includes('/')
|
||||||
|
const tmp = micromatch(input, pattern, { ...options, basename })
|
||||||
|
if (tmp.length) output.push(...tmp)
|
||||||
|
}
|
||||||
|
return [...new Set(output)]
|
||||||
|
}
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return paths
|
||||||
|
}
|
||||||
|
|
||||||
function logFn (original, minified, path, ext) {
|
function logFn (original, minified, path, ext) {
|
||||||
const saved = ((original.length - minified.length) / original.length * 100).toFixed(2)
|
const saved = ((original.length - minified.length) / original.length * 100).toFixed(2)
|
||||||
const log = this.log || console
|
const log = this.log || console
|
||||||
|
@ -106,11 +130,7 @@ function minifySvg () {
|
||||||
const routeList = route.list()
|
const routeList = route.list()
|
||||||
const { globOptions, include, verbose } = options
|
const { globOptions, include, verbose } = options
|
||||||
|
|
||||||
let includeString = include || ''
|
return Promise.all((match(routeList, include, globOptions)).map((path) => {
|
||||||
if (include && Array.isArray(include)) includeString = include.join('')
|
|
||||||
if (includeString && includeString.includes('/')) globOptions.basename = false
|
|
||||||
|
|
||||||
return Promise.all((micromatch(routeList, include, globOptions)).map((path) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const assetPath = route.get(path)
|
const assetPath = route.get(path)
|
||||||
let assetTxt = ''
|
let assetTxt = ''
|
||||||
|
@ -141,11 +161,7 @@ function gzipFn () {
|
||||||
let { level } = options
|
let { level } = options
|
||||||
if (typeof level !== 'number') level = zlib.constants.Z_BEST_COMPRESSION
|
if (typeof level !== 'number') level = zlib.constants.Z_BEST_COMPRESSION
|
||||||
|
|
||||||
let includeString = include || ''
|
return Promise.all((match(routeList, include, globOptions)).map((path) => {
|
||||||
if (include && Array.isArray(include)) includeString = include.join('')
|
|
||||||
if (includeString && includeString.includes('/')) globOptions.basename = false
|
|
||||||
|
|
||||||
return Promise.all((micromatch(routeList, include, globOptions)).map((path) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const assetPath = route.get(path)
|
const assetPath = route.get(path)
|
||||||
let assetTxt = ''
|
let assetTxt = ''
|
||||||
|
@ -176,11 +192,7 @@ function brotliFn () {
|
||||||
let { level } = options
|
let { level } = options
|
||||||
if (typeof level !== 'number') level = zlib.constants.BROTLI_MAX_QUALITY
|
if (typeof level !== 'number') level = zlib.constants.BROTLI_MAX_QUALITY
|
||||||
|
|
||||||
let includeString = include || ''
|
return Promise.all((match(routeList, include, globOptions)).map((path) => {
|
||||||
if (include && Array.isArray(include)) includeString = include.join('')
|
|
||||||
if (includeString && includeString.includes('/')) globOptions.basename = false
|
|
||||||
|
|
||||||
return Promise.all((micromatch(routeList, include, globOptions)).map((path) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const assetPath = route.get(path)
|
const assetPath = route.get(path)
|
||||||
let assetTxt = ''
|
let assetTxt = ''
|
||||||
|
|
|
@ -377,12 +377,12 @@ describe('svg', () => {
|
||||||
|
|
||||||
test('include - basename', async () => {
|
test('include - basename', async () => {
|
||||||
hexo.config.minify.svg.include = 'bar.svg'
|
hexo.config.minify.svg.include = 'bar.svg'
|
||||||
const fooPath = 'foo/bar.svg'
|
const path = 'foo/bar.svg'
|
||||||
hexo.route.set(fooPath, input)
|
hexo.route.set(path, input)
|
||||||
await s()
|
await s()
|
||||||
const { data } = await new Svgo(hexo.config.minify.svg).optimize(input)
|
const { data } = await new Svgo(hexo.config.minify.svg).optimize(input)
|
||||||
|
|
||||||
const output = hexo.route.get(fooPath)
|
const output = hexo.route.get(path)
|
||||||
let result = ''
|
let result = ''
|
||||||
output.on('data', (chunk) => (result += chunk))
|
output.on('data', (chunk) => (result += chunk))
|
||||||
output.on('end', () => {
|
output.on('end', () => {
|
||||||
|
@ -392,18 +392,99 @@ describe('svg', () => {
|
||||||
|
|
||||||
test('include - slash in pattern', async () => {
|
test('include - slash in pattern', async () => {
|
||||||
hexo.config.minify.svg.include = '**/foo/*.svg'
|
hexo.config.minify.svg.include = '**/foo/*.svg'
|
||||||
const fooPath = 'blog/site/example/foo/bar.svg'
|
const path = 'blog/site/example/foo/bar.svg'
|
||||||
hexo.route.set(fooPath, input)
|
hexo.route.set(path, input)
|
||||||
await s()
|
await s()
|
||||||
const { data } = await new Svgo(hexo.config.minify.svg).optimize(input)
|
const { data } = await new Svgo(hexo.config.minify.svg).optimize(input)
|
||||||
|
|
||||||
const output = hexo.route.get(fooPath)
|
const output = hexo.route.get(path)
|
||||||
let result = ''
|
let result = ''
|
||||||
output.on('data', (chunk) => (result += chunk))
|
output.on('data', (chunk) => (result += chunk))
|
||||||
output.on('end', () => {
|
output.on('end', () => {
|
||||||
expect(result).toBe(data)
|
expect(result).toBe(data)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('include - basename + slash', async () => {
|
||||||
|
hexo.route.remove(path)
|
||||||
|
|
||||||
|
const paths = [
|
||||||
|
'lorem/ipsum/dolor.svg',
|
||||||
|
'gravida/sociis/erat/ante.svg',
|
||||||
|
'aptent/elementum.svg',
|
||||||
|
'felis/blandit/cursus.svg'
|
||||||
|
]
|
||||||
|
hexo.config.minify.svg.include = [
|
||||||
|
'dolor.svg',
|
||||||
|
'**/sociis/**/*.svg'
|
||||||
|
]
|
||||||
|
|
||||||
|
paths.forEach((inpath) => {
|
||||||
|
hexo.route.set(inpath, input)
|
||||||
|
})
|
||||||
|
await s()
|
||||||
|
const { data } = await new Svgo(hexo.config.minify.svg).optimize(input)
|
||||||
|
|
||||||
|
const minPaths = paths.slice(0, 2)
|
||||||
|
const unminPaths = paths.slice(2)
|
||||||
|
|
||||||
|
minPaths.forEach((inpath) => {
|
||||||
|
const output = hexo.route.get(inpath)
|
||||||
|
let result = ''
|
||||||
|
output.on('data', (chunk) => (result += chunk))
|
||||||
|
output.on('end', () => {
|
||||||
|
expect(result).toBe(data)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
unminPaths.forEach((inpath) => {
|
||||||
|
const output = hexo.route.get(inpath)
|
||||||
|
let result = ''
|
||||||
|
output.on('data', (chunk) => (result += chunk))
|
||||||
|
output.on('end', () => {
|
||||||
|
expect(result).toBe(input)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('include - reverse pattern + basename disabled', async () => {
|
||||||
|
hexo.route.remove(path)
|
||||||
|
|
||||||
|
const paths = [
|
||||||
|
'lorem/ipsum/dolor.svg',
|
||||||
|
'gravida/sociis/erat/ante.svg',
|
||||||
|
'aptent/elementum.svg',
|
||||||
|
'felis/blandit/cursus.svg'
|
||||||
|
]
|
||||||
|
hexo.config.minify.svg.include = [
|
||||||
|
'!dolor.svg'
|
||||||
|
]
|
||||||
|
hexo.config.minify.svg.globOptions = {
|
||||||
|
basename: false
|
||||||
|
}
|
||||||
|
|
||||||
|
paths.forEach((inpath) => {
|
||||||
|
hexo.route.set(inpath, input)
|
||||||
|
})
|
||||||
|
await s()
|
||||||
|
const { data } = await new Svgo(hexo.config.minify.svg).optimize(input)
|
||||||
|
|
||||||
|
paths.forEach((inpath) => {
|
||||||
|
const output = hexo.route.get(inpath)
|
||||||
|
let result = ''
|
||||||
|
output.on('data', (chunk) => (result += chunk))
|
||||||
|
output.on('end', () => {
|
||||||
|
expect(result).toBe(data)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('include - empty route', async () => {
|
||||||
|
hexo.route.remove(path)
|
||||||
|
|
||||||
|
const result = await s()
|
||||||
|
expect(result.length).toBe(0)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('gzip', () => {
|
describe('gzip', () => {
|
||||||
|
@ -506,22 +587,22 @@ describe('gzip', () => {
|
||||||
|
|
||||||
test('include - basename', async () => {
|
test('include - basename', async () => {
|
||||||
hexo.config.minify.gzip.include = 'bar.txt'
|
hexo.config.minify.gzip.include = 'bar.txt'
|
||||||
const fooPath = 'foo/bar.txt'
|
const path = 'foo/bar.txt'
|
||||||
hexo.route.set(fooPath, input)
|
hexo.route.set(path, input)
|
||||||
await g()
|
await g()
|
||||||
|
|
||||||
const result = hexo.route.get(fooPath.concat('.gz'))
|
const result = hexo.route.get(path.concat('.gz'))
|
||||||
|
|
||||||
expect(result).toBeDefined()
|
expect(result).toBeDefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('include - slash in pattern', async () => {
|
test('include - slash in pattern', async () => {
|
||||||
hexo.config.minify.gzip.include = '**/foo/*.txt'
|
hexo.config.minify.gzip.include = '**/foo/*.txt'
|
||||||
const fooPath = 'blog/site/example/foo/bar.txt'
|
const path = 'blog/site/example/foo/bar.txt'
|
||||||
hexo.route.set(fooPath, input)
|
hexo.route.set(path, input)
|
||||||
await g()
|
await g()
|
||||||
|
|
||||||
const result = hexo.route.get(fooPath.concat('.gz'))
|
const result = hexo.route.get(path.concat('.gz'))
|
||||||
|
|
||||||
expect(result).toBeDefined()
|
expect(result).toBeDefined()
|
||||||
})
|
})
|
||||||
|
@ -623,22 +704,22 @@ describe('brotli', () => {
|
||||||
|
|
||||||
test('include - basename', async () => {
|
test('include - basename', async () => {
|
||||||
hexo.config.minify.brotli.include = 'bar.txt'
|
hexo.config.minify.brotli.include = 'bar.txt'
|
||||||
const fooPath = 'foo/bar.txt'
|
const path = 'foo/bar.txt'
|
||||||
hexo.route.set(fooPath, input)
|
hexo.route.set(path, input)
|
||||||
await b()
|
await b()
|
||||||
|
|
||||||
const result = hexo.route.get(fooPath.concat('.br'))
|
const result = hexo.route.get(path.concat('.br'))
|
||||||
|
|
||||||
expect(result).toBeDefined()
|
expect(result).toBeDefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('include - slash in pattern', async () => {
|
test('include - slash in pattern', async () => {
|
||||||
hexo.config.minify.brotli.include = '**/foo/*.txt'
|
hexo.config.minify.brotli.include = '**/foo/*.txt'
|
||||||
const fooPath = 'blog/site/example/foo/bar.txt'
|
const path = 'blog/site/example/foo/bar.txt'
|
||||||
hexo.route.set(fooPath, input)
|
hexo.route.set(path, input)
|
||||||
await b()
|
await b()
|
||||||
|
|
||||||
const result = hexo.route.get(fooPath.concat('.br'))
|
const result = hexo.route.get(path.concat('.br'))
|
||||||
|
|
||||||
expect(result).toBeDefined()
|
expect(result).toBeDefined()
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue