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
|
||||
this.staticRoutes = path.resolve(this.options.srcDir, this.options.dir.static)
|
||||
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.distPath,
|
||||
isUrl(this.options.build.publicPath) ? '' : this.options.build.publicPath
|
||||
|
@ -3,11 +3,14 @@ import fs from 'fs'
|
||||
|
||||
import _ from 'lodash'
|
||||
import consola from 'consola'
|
||||
import { isPureObject, isUrl } from '../common/utils'
|
||||
import { isPureObject, isUrl, guardDir } from '../common/utils'
|
||||
|
||||
import modes from './modes'
|
||||
import defaults from './nuxt.config'
|
||||
|
||||
// hasValue utility
|
||||
const hasValue = v => typeof v === 'string' && v
|
||||
|
||||
const Options = {}
|
||||
|
||||
export default Options
|
||||
@ -40,8 +43,8 @@ Options.from = function (_options) {
|
||||
options.extensions = [options.extensions]
|
||||
}
|
||||
|
||||
const hasValue = v => typeof v === 'string' && v
|
||||
options.rootDir = hasValue(options.rootDir) ? options.rootDir : process.cwd()
|
||||
// Resolve rootDir
|
||||
options.rootDir = hasValue(options.rootDir) ? path.resolve(options.rootDir) : process.cwd()
|
||||
|
||||
// Apply defaults by ${buildDir}/dist/build.config.js
|
||||
// TODO: Unsafe operation.
|
||||
@ -54,12 +57,39 @@ Options.from = function (_options) {
|
||||
// Apply defaults
|
||||
_.defaultsDeep(options, defaults)
|
||||
|
||||
// Resolve dirs
|
||||
options.srcDir = hasValue(options.srcDir)
|
||||
// Check srcDir and generate.dir excistence
|
||||
const hasSrcDir = hasValue(options.srcDir)
|
||||
const hasGenerateDir = hasValue(options.generate.dir)
|
||||
|
||||
// Resolve srcDir
|
||||
options.srcDir = hasSrcDir
|
||||
? path.resolve(options.rootDir, options.srcDir)
|
||||
: options.rootDir
|
||||
|
||||
// Resolve 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
|
||||
options.modulesDir = []
|
||||
.concat(options.modulesDir)
|
||||
|
@ -1,5 +1,6 @@
|
||||
import path from 'path'
|
||||
import _ from 'lodash'
|
||||
import consola from 'consola'
|
||||
|
||||
export const encodeHtml = function encodeHtml(str) {
|
||||
return str.replace(/</g, '<').replace(/>/g, '>')
|
||||
@ -326,3 +327,25 @@ export const createRoutes = function createRoutes(files, srcDir, pagesDir) {
|
||||
})
|
||||
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!')
|
||||
})
|
||||
})
|
||||
|
||||
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`))
|
||||
})
|
||||
})
|
||||
|
||||
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', () => {
|
||||
|
Loading…
Reference in New Issue
Block a user