applying transfer to react app

This commit is contained in:
Tyler Koenig
2021-09-20 16:54:47 -04:00
parent 8819f31dd0
commit c612b7d702
37373 changed files with 3775588 additions and 2871 deletions
+17
View File
@@ -0,0 +1,17 @@
const url = require('url')
const node = require('../node.js')
const polyfill = require('./polyfill.js')
const useNative = node.satisfies('>=10.12.0')
const fileURLToPath = (path) => {
// the polyfill is tested separately from this module, no need to hack
// process.version to try to trigger it just for coverage
// istanbul ignore next
return useNative
? url.fileURLToPath(path)
: polyfill(path)
}
module.exports = fileURLToPath
+120
View File
@@ -0,0 +1,120 @@
const { URL, domainToUnicode } = require('url')
const CHAR_LOWERCASE_A = 97
const CHAR_LOWERCASE_Z = 122
const isWindows = process.platform === 'win32'
class ERR_INVALID_FILE_URL_HOST extends TypeError {
constructor (platform) {
super(`File URL host must be "localhost" or empty on ${platform}`)
this.code = 'ERR_INVALID_FILE_URL_HOST'
}
toString () {
return `${this.name} [${this.code}]: ${this.message}`
}
}
class ERR_INVALID_FILE_URL_PATH extends TypeError {
constructor (msg) {
super(`File URL path ${msg}`)
this.code = 'ERR_INVALID_FILE_URL_PATH'
}
toString () {
return `${this.name} [${this.code}]: ${this.message}`
}
}
class ERR_INVALID_ARG_TYPE extends TypeError {
constructor (name, actual) {
super(`The "${name}" argument must be one of type string or an instance of URL. Received type ${typeof actual} ${actual}`)
this.code = 'ERR_INVALID_ARG_TYPE'
}
toString () {
return `${this.name} [${this.code}]: ${this.message}`
}
}
class ERR_INVALID_URL_SCHEME extends TypeError {
constructor (expected) {
super(`The URL must be of scheme ${expected}`)
this.code = 'ERR_INVALID_URL_SCHEME'
}
toString () {
return `${this.name} [${this.code}]: ${this.message}`
}
}
const isURLInstance = (input) => {
return input != null && input.href && input.origin
}
const getPathFromURLWin32 = (url) => {
const hostname = url.hostname
let pathname = url.pathname
for (let n = 0; n < pathname.length; n++) {
if (pathname[n] === '%') {
const third = pathname.codePointAt(n + 2) | 0x20
if ((pathname[n + 1] === '2' && third === 102) ||
(pathname[n + 1] === '5' && third === 99)) {
throw new ERR_INVALID_FILE_URL_PATH('must not include encoded \\ or / characters')
}
}
}
pathname = pathname.replace(/\//g, '\\')
pathname = decodeURIComponent(pathname)
if (hostname !== '') {
return `\\\\${domainToUnicode(hostname)}${pathname}`
}
const letter = pathname.codePointAt(1) | 0x20
const sep = pathname[2]
if (letter < CHAR_LOWERCASE_A || letter > CHAR_LOWERCASE_Z ||
(sep !== ':')) {
throw new ERR_INVALID_FILE_URL_PATH('must be absolute')
}
return pathname.slice(1)
}
const getPathFromURLPosix = (url) => {
if (url.hostname !== '') {
throw new ERR_INVALID_FILE_URL_HOST(process.platform)
}
const pathname = url.pathname
for (let n = 0; n < pathname.length; n++) {
if (pathname[n] === '%') {
const third = pathname.codePointAt(n + 2) | 0x20
if (pathname[n + 1] === '2' && third === 102) {
throw new ERR_INVALID_FILE_URL_PATH('must not include encoded / characters')
}
}
}
return decodeURIComponent(pathname)
}
const fileURLToPath = (path) => {
if (typeof path === 'string') {
path = new URL(path)
} else if (!isURLInstance(path)) {
throw new ERR_INVALID_ARG_TYPE('path', ['string', 'URL'], path)
}
if (path.protocol !== 'file:') {
throw new ERR_INVALID_URL_SCHEME('file')
}
return isWindows
? getPathFromURLWin32(path)
: getPathFromURLPosix(path)
}
module.exports = fileURLToPath
+20
View File
@@ -0,0 +1,20 @@
// given an input that may or may not be an object, return an object that has
// a copy of every defined property listed in 'copy'. if the input is not an
// object, assign it to the property named by 'wrap'
const getOptions = (input, { copy, wrap }) => {
const result = {}
if (input && typeof input === 'object') {
for (const prop of copy) {
if (input[prop] !== undefined) {
result[prop] = input[prop]
}
}
} else {
result[wrap] = input
}
return result
}
module.exports = getOptions
+9
View File
@@ -0,0 +1,9 @@
const semver = require('semver')
const satisfies = (range) => {
return semver.satisfies(process.version, range, { includePrerelease: true })
}
module.exports = {
satisfies,
}
+92
View File
@@ -0,0 +1,92 @@
const { dirname, resolve } = require('path')
const fileURLToPath = require('./file-url-to-path/index.js')
const fs = require('../fs.js')
// given a path, find the owner of the nearest parent
const find = async (path) => {
// if we have no getuid, permissions are irrelevant on this platform
if (!process.getuid) {
return {}
}
// fs methods accept URL objects with a scheme of file: so we need to unwrap
// those into an actual path string before we can resolve it
const resolved = path != null && path.href && path.origin
? resolve(fileURLToPath(path))
: resolve(path)
let stat
try {
stat = await fs.lstat(resolved)
} finally {
// if we got a stat, return its contents
if (stat) {
return { uid: stat.uid, gid: stat.gid }
}
// try the parent directory
if (resolved !== dirname(resolved)) {
return find(dirname(resolved))
}
// no more parents, never got a stat, just return an empty object
return {}
}
}
// given a path, uid, and gid update the ownership of the path if necessary
const update = async (path, uid, gid) => {
// nothing to update, just exit
if (uid === undefined && gid === undefined) {
return
}
try {
// see if the permissions are already the same, if they are we don't
// need to do anything, so return early
const stat = await fs.stat(path)
if (uid === stat.uid && gid === stat.gid) {
return
}
} catch (err) {}
try {
await fs.chown(path, uid, gid)
} catch (err) {}
}
// accepts a `path` and the `owner` property of an options object and normalizes
// it into an object with numerical `uid` and `gid`
const validate = async (path, input) => {
let uid
let gid
if (typeof input === 'string' || typeof input === 'number') {
uid = input
gid = input
} else if (input && typeof input === 'object') {
uid = input.uid
gid = input.gid
}
if (uid === 'inherit' || gid === 'inherit') {
const owner = await find(path)
if (uid === 'inherit') {
uid = owner.uid
}
if (gid === 'inherit') {
gid = owner.gid
}
}
return { uid, gid }
}
module.exports = {
find,
update,
validate,
}
+22
View File
@@ -0,0 +1,22 @@
const fs = require('./fs.js')
const getOptions = require('./common/get-options.js')
const owner = require('./common/owner.js')
const copyFile = async (src, dest, opts) => {
const options = getOptions(opts, {
copy: ['mode', 'owner'],
wrap: 'mode',
})
const { uid, gid } = await owner.validate(dest, options.owner)
// the node core method as of 16.5.0 does not support the mode being in an
// object, so we have to pass the mode value directly
const result = await fs.copyFile(src, dest, options.mode)
await owner.update(dest, uid, gid)
return result
}
module.exports = copyFile
+8
View File
@@ -0,0 +1,8 @@
const fs = require('fs')
const promisify = require('@gar/promisify')
// this module returns the core fs module wrapped in a proxy that promisifies
// method calls within the getter. we keep it in a separate module so that the
// overridden methods have a consistent way to get to promisified fs methods
// without creating a circular dependency
module.exports = promisify(fs)
+9
View File
@@ -0,0 +1,9 @@
module.exports = {
...require('./fs.js'),
copyFile: require('./copy-file.js'),
mkdir: require('./mkdir/index.js'),
mkdtemp: require('./mkdtemp.js'),
rm: require('./rm/index.js'),
withTempDir: require('./with-temp-dir.js'),
writeFile: require('./write-file.js'),
}
+32
View File
@@ -0,0 +1,32 @@
const fs = require('../fs.js')
const getOptions = require('../common/get-options.js')
const node = require('../common/node.js')
const owner = require('../common/owner.js')
const polyfill = require('./polyfill.js')
// node 10.12.0 added the options parameter, which allows recursive and mode
// properties to be passed
const useNative = node.satisfies('>=10.12.0')
// extends mkdir with the ability to specify an owner of the new dir
const mkdir = async (path, opts) => {
const options = getOptions(opts, {
copy: ['mode', 'recursive', 'owner'],
wrap: 'mode',
})
const { uid, gid } = await owner.validate(path, options.owner)
// the polyfill is tested separately from this module, no need to hack
// process.version to try to trigger it just for coverage
// istanbul ignore next
const result = useNative
? await fs.mkdir(path, options)
: await polyfill(path, options)
await owner.update(path, uid, gid)
return result
}
module.exports = mkdir
+81
View File
@@ -0,0 +1,81 @@
const { dirname } = require('path')
const fileURLToPath = require('../common/file-url-to-path/index.js')
const fs = require('../fs.js')
const defaultOptions = {
mode: 0o777,
recursive: false,
}
const mkdir = async (path, opts) => {
const options = { ...defaultOptions, ...opts }
// if we're not in recursive mode, just call the real mkdir with the path and
// the mode option only
if (!options.recursive) {
return fs.mkdir(path, options.mode)
}
const makeDirectory = async (dir, mode) => {
// we can't use dirname directly since these functions support URL
// objects with the file: protocol as the path input, so first we get a
// string path, then we can call dirname on that
const parent = dir != null && dir.href && dir.origin
? dirname(fileURLToPath(dir))
: dirname(dir)
// if the parent is the dir itself, try to create it. anything but EISDIR
// should be rethrown
if (parent === dir) {
try {
await fs.mkdir(dir, opts)
} catch (err) {
if (err.code !== 'EISDIR') {
throw err
}
}
return undefined
}
try {
await fs.mkdir(dir, mode)
return dir
} catch (err) {
// ENOENT means the parent wasn't there, so create that
if (err.code === 'ENOENT') {
const made = await makeDirectory(parent, mode)
await makeDirectory(dir, mode)
// return the shallowest path we created, i.e. the result of creating
// the parent
return made
}
// an EEXIST means there's already something there
// an EROFS means we have a read-only filesystem and can't create a dir
// any other error is fatal and we should give up now
if (err.code !== 'EEXIST' && err.code !== 'EROFS') {
throw err
}
// stat the directory, if the result is a directory, then we successfully
// created this one so return its path. otherwise, we reject with the
// original error by ignoring the error in the catch
try {
const stat = await fs.stat(dir)
if (stat.isDirectory()) {
// if it already existed, we didn't create anything so return
// undefined
return undefined
}
} catch (_) {}
// if the thing that's there isn't a directory, then just re-throw
throw err
}
}
return makeDirectory(path, options.mode)
}
module.exports = mkdir
+28
View File
@@ -0,0 +1,28 @@
const { dirname, sep } = require('path')
const fs = require('./fs.js')
const getOptions = require('./common/get-options.js')
const owner = require('./common/owner.js')
const mkdtemp = async (prefix, opts) => {
const options = getOptions(opts, {
copy: ['encoding', 'owner'],
wrap: 'encoding',
})
// mkdtemp relies on the trailing path separator to indicate if it should
// create a directory inside of the prefix. if that's the case then the root
// we infer ownership from is the prefix itself, otherwise it's the dirname
// /tmp -> /tmpABCDEF, infers from /
// /tmp/ -> /tmp/ABCDEF, infers from /tmp
const root = prefix.endsWith(sep) ? prefix : dirname(prefix)
const { uid, gid } = await owner.validate(root, options.owner)
const result = await fs.mkdtemp(prefix, options)
await owner.update(result, uid, gid)
return result
}
module.exports = mkdtemp
+22
View File
@@ -0,0 +1,22 @@
const fs = require('../fs.js')
const getOptions = require('../common/get-options.js')
const node = require('../common/node.js')
const polyfill = require('./polyfill.js')
// node 14.14.0 added fs.rm, which allows both the force and recursive options
const useNative = node.satisfies('>=14.14.0')
const rm = async (path, opts) => {
const options = getOptions(opts, {
copy: ['retryDelay', 'maxRetries', 'recursive', 'force'],
})
// the polyfill is tested separately from this module, no need to hack
// process.version to try to trigger it just for coverage
// istanbul ignore next
return useNative
? fs.rm(path, options)
: polyfill(path, options)
}
module.exports = rm
+238
View File
@@ -0,0 +1,238 @@
// this file is a modified version of the code in node core >=14.14.0
// which is, in turn, a modified version of the rimraf module on npm
// node core changes:
// - Use of the assert module has been replaced with core's error system.
// - All code related to the glob dependency has been removed.
// - Bring your own custom fs module is not currently supported.
// - Some basic code cleanup.
// changes here:
// - remove all callback related code
// - drop sync support
// - change assertions back to non-internal methods (see options.js)
// - throws ENOTDIR when rmdir gets an ENOENT for a path that exists in Windows
const errnos = require('os').constants.errno
const { join } = require('path')
const fs = require('../fs.js')
// error codes that mean we need to remove contents
const notEmptyCodes = new Set([
'ENOTEMPTY',
'EEXIST',
'EPERM',
])
// error codes we can retry later
const retryCodes = new Set([
'EBUSY',
'EMFILE',
'ENFILE',
'ENOTEMPTY',
'EPERM',
])
const isWindows = process.platform === 'win32'
const defaultOptions = {
retryDelay: 100,
maxRetries: 0,
recursive: false,
force: false,
}
// this is drastically simplified, but should be roughly equivalent to what
// node core throws
class ERR_FS_EISDIR extends Error {
constructor (path) {
super()
this.info = {
code: 'EISDIR',
message: 'is a directory',
path,
syscall: 'rm',
errno: errnos.EISDIR,
}
this.name = 'SystemError'
this.code = 'ERR_FS_EISDIR'
this.errno = errnos.EISDIR
this.syscall = 'rm'
this.path = path
this.message = `Path is a directory: ${this.syscall} returned ${this.info.code} (is a directory) ${path}`
}
toString () {
return `${this.name} [${this.code}]: ${this.message}`
}
}
class ENOTDIR extends Error {
constructor (path) {
super()
this.name = 'Error'
this.code = 'ENOTDIR'
this.errno = errnos.ENOTDIR
this.syscall = 'rmdir'
this.path = path
this.message = `not a directory, ${this.syscall} '${this.path}'`
}
toString () {
return `${this.name}: ${this.code}: ${this.message}`
}
}
// force is passed separately here because we respect it for the first entry
// into rimraf only, any further calls that are spawned as a result (i.e. to
// delete content within the target) will ignore ENOENT errors
const rimraf = async (path, options, isTop = false) => {
const force = isTop ? options.force : true
const stat = await fs.lstat(path)
.catch((err) => {
// we only ignore ENOENT if we're forcing this call
if (err.code === 'ENOENT' && force) {
return
}
if (isWindows && err.code === 'EPERM') {
return fixEPERM(path, options, err, isTop)
}
throw err
})
// no stat object here means either lstat threw an ENOENT, or lstat threw
// an EPERM and the fixPERM function took care of things. either way, we're
// already done, so return early
if (!stat) {
return
}
if (stat.isDirectory()) {
return rmdir(path, options, null, isTop)
}
return fs.unlink(path)
.catch((err) => {
if (err.code === 'ENOENT' && force) {
return
}
if (err.code === 'EISDIR') {
return rmdir(path, options, err, isTop)
}
if (err.code === 'EPERM') {
// in windows, we handle this through fixEPERM which will also try to
// delete things again. everywhere else since deleting the target as a
// file didn't work we go ahead and try to delete it as a directory
return isWindows
? fixEPERM(path, options, err, isTop)
: rmdir(path, options, err, isTop)
}
throw err
})
}
const fixEPERM = async (path, options, originalErr, isTop) => {
const force = isTop ? options.force : true
const targetMissing = await fs.chmod(path, 0o666)
.catch((err) => {
if (err.code === 'ENOENT' && force) {
return true
}
throw originalErr
})
// got an ENOENT above, return now. no file = no problem
if (targetMissing) {
return
}
// this function does its own lstat rather than calling rimraf again to avoid
// infinite recursion for a repeating EPERM
const stat = await fs.lstat(path)
.catch((err) => {
if (err.code === 'ENOENT' && force) {
return
}
throw originalErr
})
if (!stat) {
return
}
if (stat.isDirectory()) {
return rmdir(path, options, originalErr, isTop)
}
return fs.unlink(path)
}
const rmdir = async (path, options, originalErr, isTop) => {
if (!options.recursive && isTop) {
throw originalErr || new ERR_FS_EISDIR(path)
}
const force = isTop ? options.force : true
return fs.rmdir(path)
.catch(async (err) => {
// in Windows, calling rmdir on a file path will fail with ENOENT rather
// than ENOTDIR. to determine if that's what happened, we have to do
// another lstat on the path. if the path isn't actually gone, we throw
// away the ENOENT and replace it with our own ENOTDIR
if (isWindows && err.code === 'ENOENT') {
const stillExists = await fs.lstat(path).then(() => true, () => false)
if (stillExists) {
err = new ENOTDIR(path)
}
}
// not there, not a problem
if (err.code === 'ENOENT' && force) {
return
}
// we may not have originalErr if lstat tells us our target is a
// directory but that changes before we actually remove it, so
// only throw it here if it's set
if (originalErr && err.code === 'ENOTDIR') {
throw originalErr
}
// the directory isn't empty, remove the contents and try again
if (notEmptyCodes.has(err.code)) {
const files = await fs.readdir(path)
await Promise.all(files.map((file) => {
const target = join(path, file)
return rimraf(target, options)
}))
return fs.rmdir(path)
}
throw err
})
}
const rm = async (path, opts) => {
const options = { ...defaultOptions, ...opts }
let retries = 0
const errHandler = async (err) => {
if (retryCodes.has(err.code) && ++retries < options.maxRetries) {
const delay = retries * options.retryDelay
await promiseTimeout(delay)
return rimraf(path, options, true).catch(errHandler)
}
throw err
}
return rimraf(path, options, true).catch(errHandler)
}
const promiseTimeout = (ms) => new Promise((r) => setTimeout(r, ms))
module.exports = rm
+39
View File
@@ -0,0 +1,39 @@
const { join, sep } = require('path')
const getOptions = require('./common/get-options.js')
const mkdir = require('./mkdir/index.js')
const mkdtemp = require('./mkdtemp.js')
const rm = require('./rm/index.js')
// create a temp directory, ensure its permissions match its parent, then call
// the supplied function passing it the path to the directory. clean up after
// the function finishes, whether it throws or not
const withTempDir = async (root, fn, opts) => {
const options = getOptions(opts, {
copy: ['tmpPrefix'],
})
// create the directory, and fix its ownership
await mkdir(root, { recursive: true, owner: 'inherit' })
const target = await mkdtemp(join(`${root}${sep}`, options.tmpPrefix || ''), { owner: 'inherit' })
let err
let result
try {
result = await fn(target)
} catch (_err) {
err = _err
}
try {
await rm(target, { force: true, recursive: true })
} catch (err) {}
if (err) {
throw err
}
return result
}
module.exports = withTempDir
+19
View File
@@ -0,0 +1,19 @@
const fs = require('./fs.js')
const getOptions = require('./common/get-options.js')
const owner = require('./common/owner.js')
const writeFile = async (file, data, opts) => {
const options = getOptions(opts, {
copy: ['encoding', 'mode', 'flag', 'signal', 'owner'],
wrap: 'encoding',
})
const { uid, gid } = await owner.validate(file, options.owner)
const result = await fs.writeFile(file, data, options)
await owner.update(file, uid, gid)
return result
}
module.exports = writeFile