mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-23 14:15:13 +00:00
fix: prevent removing project by mistake due to build or generate paths (#3869)
This commit is contained in:
parent
40ad691f60
commit
226b90d4ae
@ -15,7 +15,7 @@ export default class Generator {
|
|||||||
// Set variables
|
// Set variables
|
||||||
this.staticRoutes = path.resolve(this.options.srcDir, this.options.dir.static)
|
this.staticRoutes = path.resolve(this.options.srcDir, this.options.dir.static)
|
||||||
this.srcBuiltPath = path.resolve(this.options.buildDir, 'dist', 'client')
|
this.srcBuiltPath = path.resolve(this.options.buildDir, 'dist', 'client')
|
||||||
this.distPath = path.resolve(this.options.rootDir, this.options.generate.dir)
|
this.distPath = this.options.generate.dir
|
||||||
this.distNuxtPath = path.join(
|
this.distNuxtPath = path.join(
|
||||||
this.distPath,
|
this.distPath,
|
||||||
isUrl(this.options.build.publicPath) ? '' : this.options.build.publicPath
|
isUrl(this.options.build.publicPath) ? '' : this.options.build.publicPath
|
||||||
|
@ -3,11 +3,14 @@ import fs from 'fs'
|
|||||||
|
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import { isPureObject, isUrl } from '../common/utils'
|
import { isPureObject, isUrl, guardDir } from '../common/utils'
|
||||||
|
|
||||||
import modes from './modes'
|
import modes from './modes'
|
||||||
import defaults from './nuxt.config'
|
import defaults from './nuxt.config'
|
||||||
|
|
||||||
|
// hasValue utility
|
||||||
|
const hasValue = v => typeof v === 'string' && v
|
||||||
|
|
||||||
const Options = {}
|
const Options = {}
|
||||||
|
|
||||||
export default Options
|
export default Options
|
||||||
@ -40,8 +43,8 @@ Options.from = function (_options) {
|
|||||||
options.extensions = [options.extensions]
|
options.extensions = [options.extensions]
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasValue = v => typeof v === 'string' && v
|
// Resolve rootDir
|
||||||
options.rootDir = hasValue(options.rootDir) ? options.rootDir : process.cwd()
|
options.rootDir = hasValue(options.rootDir) ? path.resolve(options.rootDir) : process.cwd()
|
||||||
|
|
||||||
// Apply defaults by ${buildDir}/dist/build.config.js
|
// Apply defaults by ${buildDir}/dist/build.config.js
|
||||||
// TODO: Unsafe operation.
|
// TODO: Unsafe operation.
|
||||||
@ -54,12 +57,39 @@ Options.from = function (_options) {
|
|||||||
// Apply defaults
|
// Apply defaults
|
||||||
_.defaultsDeep(options, defaults)
|
_.defaultsDeep(options, defaults)
|
||||||
|
|
||||||
// Resolve dirs
|
// Check srcDir and generate.dir excistence
|
||||||
options.srcDir = hasValue(options.srcDir)
|
const hasSrcDir = hasValue(options.srcDir)
|
||||||
|
const hasGenerateDir = hasValue(options.generate.dir)
|
||||||
|
|
||||||
|
// Resolve srcDir
|
||||||
|
options.srcDir = hasSrcDir
|
||||||
? path.resolve(options.rootDir, options.srcDir)
|
? path.resolve(options.rootDir, options.srcDir)
|
||||||
: options.rootDir
|
: options.rootDir
|
||||||
|
|
||||||
|
// Resolve buildDir
|
||||||
options.buildDir = path.resolve(options.rootDir, options.buildDir)
|
options.buildDir = path.resolve(options.rootDir, options.buildDir)
|
||||||
|
|
||||||
|
// Protect rootDir against buildDir
|
||||||
|
guardDir(options, 'rootDir', 'buildDir')
|
||||||
|
|
||||||
|
if (hasGenerateDir) {
|
||||||
|
// Resolve generate.dir
|
||||||
|
options.generate.dir = path.resolve(options.rootDir, options.generate.dir)
|
||||||
|
|
||||||
|
// Protect rootDir against buildDir
|
||||||
|
guardDir(options, 'rootDir', 'generate.dir')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasSrcDir) {
|
||||||
|
// Protect srcDir against buildDir
|
||||||
|
guardDir(options, 'srcDir', 'buildDir')
|
||||||
|
|
||||||
|
if (hasGenerateDir) {
|
||||||
|
// Protect srcDir against generate.dir
|
||||||
|
guardDir(options, 'srcDir', 'generate.dir')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Populate modulesDir
|
// Populate modulesDir
|
||||||
options.modulesDir = []
|
options.modulesDir = []
|
||||||
.concat(options.modulesDir)
|
.concat(options.modulesDir)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
import consola from 'consola'
|
||||||
|
|
||||||
export const encodeHtml = function encodeHtml(str) {
|
export const encodeHtml = function encodeHtml(str) {
|
||||||
return str.replace(/</g, '<').replace(/>/g, '>')
|
return str.replace(/</g, '<').replace(/>/g, '>')
|
||||||
@ -326,3 +327,25 @@ export const createRoutes = function createRoutes(files, srcDir, pagesDir) {
|
|||||||
})
|
})
|
||||||
return cleanChildrenRoutes(routes)
|
return cleanChildrenRoutes(routes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Guard dir1 from dir2 which can be indiscriminately removed
|
||||||
|
export const guardDir = function guardDir(options, key1, key2) {
|
||||||
|
const dir1 = _.get(options, key1, false)
|
||||||
|
const dir2 = _.get(options, key2, false)
|
||||||
|
|
||||||
|
if (
|
||||||
|
dir1 &&
|
||||||
|
dir2 &&
|
||||||
|
(
|
||||||
|
dir1 === dir2 ||
|
||||||
|
(
|
||||||
|
dir1.startsWith(dir2) &&
|
||||||
|
!path.basename(dir1).startsWith(path.basename(dir2))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
const errorMessage = `options.${key2} cannot be a parent of or same as ${key1}`
|
||||||
|
consola.fatal(errorMessage)
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -17,4 +17,14 @@ describe('basic fail generate', () => {
|
|||||||
expect(e.message).toBe('Not today!')
|
expect(e.message).toBe('Not today!')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('Fail when generate.dir equals rootDir', async () => {
|
||||||
|
const options = await loadFixture('basic', {
|
||||||
|
generate: { dir: '../basic' }
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
new Nuxt(options) /* eslint-disable-line no-new */
|
||||||
|
}).toThrow(/options.generate.dir cannot be/)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -236,6 +236,53 @@ describe('utils', () => {
|
|||||||
.toBe(Utils.wp(`loader1!loader2!..${path.sep}baz`))
|
.toBe(Utils.wp(`loader1!loader2!..${path.sep}baz`))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('guardDir', () => {
|
||||||
|
test('Parent dir is guarded', () => {
|
||||||
|
expect(() => {
|
||||||
|
Utils.guardDir({
|
||||||
|
dir1: '/root/parent',
|
||||||
|
dir2: '/root'
|
||||||
|
}, 'dir1', 'dir2')
|
||||||
|
}).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Same dir is guarded', () => {
|
||||||
|
expect(() => {
|
||||||
|
Utils.guardDir({
|
||||||
|
dir1: '/root/parent',
|
||||||
|
dir2: '/root/parent'
|
||||||
|
}, 'dir1', 'dir2')
|
||||||
|
}).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Same level dir is not guarded', () => {
|
||||||
|
expect(() => {
|
||||||
|
Utils.guardDir({
|
||||||
|
dir1: '/root/parent-next',
|
||||||
|
dir2: '/root/parent'
|
||||||
|
}, 'dir1', 'dir2')
|
||||||
|
}).not.toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Same level dir is not guarded 2', () => {
|
||||||
|
expect(() => {
|
||||||
|
Utils.guardDir({
|
||||||
|
dir1: '/root/parent',
|
||||||
|
dir2: '/root/parent-next'
|
||||||
|
}, 'dir1', 'dir2')
|
||||||
|
}).not.toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Child dir is not guarded', () => {
|
||||||
|
expect(() => {
|
||||||
|
Utils.guardDir({
|
||||||
|
dir1: '/root/parent',
|
||||||
|
dir2: '/root/parent/child'
|
||||||
|
}, 'dir1', 'dir2')
|
||||||
|
}).not.toThrow()
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
test('createRoutes should allow snake case routes', () => {
|
test('createRoutes should allow snake case routes', () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user