@ayonli/jsext
Advanced tools
Comparing version 0.9.6 to 0.9.7
@@ -58,3 +58,3 @@ /** | ||
} else { | ||
return new ByteArray(data as any); | ||
return new ByteArray(data); | ||
} | ||
@@ -61,0 +61,0 @@ } |
@@ -159,3 +159,3 @@ 'use strict'; | ||
const listeners = [...stdin.listeners("data")]; | ||
if (listeners === null || listeners === void 0 ? void 0 : listeners.length) { | ||
if (listeners.length) { | ||
stdin.removeAllListeners("data"); | ||
@@ -169,3 +169,3 @@ } | ||
stdin.setRawMode(false); | ||
if (listeners === null || listeners === void 0 ? void 0 : listeners.length) { | ||
if (listeners.length) { | ||
listeners.forEach(listener => stdin.addListener("data", listener)); | ||
@@ -172,0 +172,0 @@ } |
'use strict'; | ||
var path = require('../path.js'); | ||
var env = require('../env.js'); | ||
@@ -8,3 +7,2 @@ var runtime = require('../runtime.js'); | ||
var reader = require('../reader.js'); | ||
var dialog_terminal_util = require('./terminal/util.js'); | ||
var dialog_terminal_file_mac = require('./terminal/file/mac.js'); | ||
@@ -16,4 +14,4 @@ var dialog_terminal_file_linux = require('./terminal/file/linux.js'); | ||
var fs = require('../fs.js'); | ||
var fs_types = require('../fs/types.js'); | ||
var object = require('../object.js'); | ||
var reader_util = require('../reader/util.js'); | ||
var cli_common = require('../cli/common.js'); | ||
@@ -107,2 +105,3 @@ | ||
async function openFile(options = {}) { | ||
var _a, _b; | ||
const { title = "", type = "", multiple = false, directory = false } = options; | ||
@@ -115,21 +114,14 @@ if (directory && typeof globalThis["showDirectoryPicker"] === "function") { | ||
} | ||
await (async function walk(dir, base = "") { | ||
const entries = dir.entries(); | ||
for await (const [_, entry] of entries) { | ||
const path$1 = path.join(base, entry.name); | ||
if (entry.kind === "file") { | ||
const file = await entry.getFile(); | ||
Object.defineProperty(file, "webkitRelativePath", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: false, | ||
value: path$1 !== null && path$1 !== void 0 ? path$1 : "", | ||
}); | ||
files.push(file); | ||
} | ||
else { | ||
await walk(entry, path$1); | ||
} | ||
for await (const entry of fs.readDir(dir, { recursive: true })) { | ||
if (entry.kind === "file") { | ||
const file = await entry.handle.getFile(); | ||
Object.defineProperty(file, "webkitRelativePath", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: false, | ||
value: (_a = entry.path) !== null && _a !== void 0 ? _a : "", | ||
}); | ||
files.push(fs_types.fixFileType(file)); | ||
} | ||
})(dir); | ||
} | ||
return files; | ||
@@ -143,3 +135,3 @@ } | ||
const file = await handle.getFile(); | ||
files.push(file); | ||
files.push(fs_types.fixFileType(file)); | ||
} | ||
@@ -150,3 +142,3 @@ return files; | ||
const handle = await dialog_terminal_file_browser.browserPickFile(type); | ||
return handle ? await handle.getFile() : null; | ||
return handle ? await handle.getFile().then(fs_types.fixFileType) : null; | ||
} | ||
@@ -201,53 +193,22 @@ } | ||
if (dirname) { | ||
const folder = path.basename(dirname); | ||
const files = []; | ||
if (typeof Deno === "object") { | ||
await (async function walk(dirname, relativePath = "") { | ||
for await (const entry of Deno.readDir(dirname)) { | ||
if (entry.isFile) { | ||
files.push({ | ||
path: path.join(dirname, entry.name), | ||
relativePath: relativePath + "/" + entry.name, | ||
}); | ||
} | ||
else if (entry.isDirectory) { | ||
await walk(path.join(dirname, entry.name), relativePath + "/" + entry.name); | ||
} | ||
else if (entry.isSymlink) { | ||
const symlink = await Deno.readLink(path.join(dirname, entry.name)); | ||
await walk(symlink, relativePath + "/" + entry.name); | ||
} | ||
} | ||
})(dirname, folder); | ||
for await (const entry of fs.readDir(dirname, { recursive: true })) { | ||
if (entry.kind === "file") { | ||
const file = await entry.handle.getFile(); | ||
Object.defineProperty(file, "webkitRelativePath", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: false, | ||
value: (_b = entry.path) !== null && _b !== void 0 ? _b : "", | ||
}); | ||
files.push(fs_types.fixFileType(file)); | ||
} | ||
} | ||
else { | ||
const { readdir, readlink } = await import('fs/promises'); | ||
await (async function walk(dirname, relativePath = "") { | ||
const entries = await readdir(dirname, { withFileTypes: true }); | ||
for (const entry of entries) { | ||
if (entry.isFile()) { | ||
files.push({ | ||
path: path.join(dirname, entry.name), | ||
relativePath: relativePath + "/" + entry.name, | ||
}); | ||
} | ||
else if (entry.isDirectory()) { | ||
await walk(path.join(dirname, entry.name), relativePath + "/" + entry.name); | ||
} | ||
else if (entry.isSymbolicLink()) { | ||
const symlink = await readlink(path.join(dirname, entry.name)); | ||
await walk(symlink, relativePath + "/" + entry.name); | ||
} | ||
} | ||
})(dirname, folder); | ||
} | ||
return await Promise.all(files.map(({ path, relativePath }) => { | ||
return dialog_terminal_util.readFile(path, relativePath); | ||
})); | ||
return files; | ||
} | ||
else if (filenames) { | ||
return await Promise.all(filenames.map(path => dialog_terminal_util.readFile(path))); | ||
return await Promise.all(filenames.map(path => fs.readFileAsFile(path))); | ||
} | ||
else if (filename) { | ||
return await dialog_terminal_util.readFile(filename); | ||
return await fs.readFileAsFile(filename); | ||
} | ||
@@ -266,3 +227,3 @@ else if (directory || multiple) { | ||
async function saveFile(file, options = {}) { | ||
var _a; | ||
var _a, _b; | ||
if (typeof globalThis["showSaveFilePicker"] === "function") { | ||
@@ -272,3 +233,3 @@ try { | ||
forSave: true, | ||
defaultName: options.name || ((_a = object.as(file, Blob)) === null || _a === void 0 ? void 0 : _a.name), | ||
defaultName: options.name || ((_a = object.as(file, File)) === null || _a === void 0 ? void 0 : _a.name), | ||
}); | ||
@@ -313,35 +274,12 @@ if (handle) { | ||
const { title } = options; | ||
let stream; | ||
let filename; | ||
if (typeof ReadableStream === "function" && file instanceof ReadableStream) { | ||
stream = file; | ||
if (typeof Blob === "function" && file instanceof Blob) { | ||
filename = await pickFile({ | ||
title, | ||
type: options.type, | ||
forSave: true, | ||
defaultName: options.name, | ||
}); | ||
} | ||
else if (typeof File === "function" && file instanceof File) { | ||
stream = file.stream(); | ||
filename = await pickFile({ | ||
title, | ||
type: file.type, | ||
forSave: true, | ||
defaultName: options.name || file.name, | ||
}); | ||
} | ||
else if (typeof Blob === "function" && file instanceof Blob) { | ||
stream = file.stream(); | ||
filename = await pickFile({ | ||
title, | ||
type: options.type || file.type, | ||
forSave: true, | ||
defaultName: options.name, | ||
defaultName: options.name || ((_b = object.as(file, File)) === null || _b === void 0 ? void 0 : _b.name), | ||
}); | ||
} | ||
else { | ||
const type = options.type || "application/octet-stream"; | ||
const blob = new Blob([file], { type }); | ||
stream = blob.stream(); | ||
filename = await pickFile({ | ||
@@ -355,13 +293,3 @@ title, | ||
if (filename) { | ||
if (typeof Deno === "object") { | ||
await Deno.writeFile(filename, stream, { create: true }); | ||
} | ||
else { | ||
const { createWriteStream } = await import('fs'); | ||
const out = createWriteStream(filename, { flags: "w" }); | ||
for await (const chunk of reader_util.toAsyncIterable(stream)) { | ||
out.write(chunk); | ||
} | ||
out.close(); | ||
} | ||
await fs.writeFile(filename, file); | ||
} | ||
@@ -368,0 +296,0 @@ } |
'use strict'; | ||
var path = require('../../path.js'); | ||
var filetype = require('../../filetype.js'); | ||
function escape(str) { | ||
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); | ||
} | ||
function createFileObject(content, path$1, options) { | ||
var _a; | ||
const { lastModified, relativePath } = options; | ||
const filename = path.basename(path$1); | ||
const type = (_a = filetype.getMIME(path.extname(filename))) !== null && _a !== void 0 ? _a : ""; | ||
let file; | ||
if (lastModified) { | ||
file = new File([content], filename, { type, lastModified }); | ||
} | ||
else { | ||
file = new File([content], path$1, { type }); | ||
} | ||
Object.defineProperty(file, "webkitRelativePath", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: false, | ||
value: relativePath !== null && relativePath !== void 0 ? relativePath : "", | ||
}); | ||
return file; | ||
} | ||
async function readFile(path, relativePath = "") { | ||
let content; | ||
let lastModified; | ||
if (typeof Deno === "object") { | ||
const stats = await Deno.stat(path); | ||
content = await Deno.readFile(path); | ||
lastModified = stats.mtime ? stats.mtime.valueOf() : 0; | ||
} | ||
else { | ||
const { readFile, stat } = await import('fs/promises'); | ||
const stats = await stat(path); | ||
content = await readFile(path); | ||
lastModified = stats.mtimeMs; | ||
} | ||
return createFileObject(content, path, { relativePath, lastModified }); | ||
} | ||
exports.createFileObject = createFileObject; | ||
exports.escape = escape; | ||
exports.readFile = readFile; | ||
//# sourceMappingURL=util.js.map |
@@ -17,3 +17,3 @@ 'use strict'; | ||
const isBun = typeof Bun === "object" && !!Bun.version; | ||
const isNodeLike = typeof process === "object" && !!((_b = process.versions) === null || _b === void 0 ? void 0 : _b.node); | ||
const isNodeLike = typeof process === "object" && !!((_b = process.versions) === null || _b === void 0 ? void 0 : _b.node) && !isDeno; | ||
const isNode = isNodeLike && !isDeno && !isBun; | ||
@@ -20,0 +20,0 @@ const isNodeBelow14 = isNode && parseInt(process.version.slice(1)) < 14; |
207
cjs/fs.js
@@ -10,2 +10,3 @@ 'use strict'; | ||
var filetype = require('./filetype.js'); | ||
var fs_types = require('./fs/types.js'); | ||
var path = require('./path.js'); | ||
@@ -645,46 +646,6 @@ var reader = require('./reader.js'); | ||
async function readFileHandleAsFile(handle) { | ||
var _a; | ||
const file = await rawOp(handle.getFile(), "file"); | ||
if (!file.type) { | ||
const ext = path.extname(file.name); | ||
if (ext) { | ||
Object.defineProperty(file, "type", { | ||
value: (_a = filetype.getMIME(ext)) !== null && _a !== void 0 ? _a : "", | ||
writable: false, | ||
configurable: true, | ||
}); | ||
} | ||
} | ||
return file; | ||
return fs_types.fixFileType(file); | ||
} | ||
/** | ||
* Reads the file as a `ReadableStream`. | ||
*/ | ||
function readFileAsStream(target, options = {}) { | ||
return reader_util.resolveByteStream((async () => { | ||
if (typeof target === "object") { | ||
return await readFileHandleAsStream(target); | ||
} | ||
const filename = target; | ||
if (env.isDeno) { | ||
const file = await rawOp(Deno.open(filename, { read: true })); | ||
return file.readable; | ||
} | ||
else if (env.isNodeLike) { | ||
const filename = target; | ||
const fs = await import('fs'); | ||
const reader$1 = fs.createReadStream(filename); | ||
return reader.toReadableStream(reader$1); | ||
} | ||
else { | ||
const handle = await getFileHandle(filename, { root: options.root }); | ||
return await readFileHandleAsStream(handle); | ||
} | ||
})()); | ||
} | ||
async function readFileHandleAsStream(handle) { | ||
const file = await rawOp(handle.getFile(), "file"); | ||
return file.stream(); | ||
} | ||
/** | ||
* Writes the given data to the file. | ||
@@ -712,24 +673,29 @@ */ | ||
else if (env.isNodeLike) { | ||
const fs = await import('fs/promises'); | ||
const { append, ...rest } = options; | ||
let _data; | ||
if (typeof Blob === "function" && data instanceof Blob) { | ||
_data = new Uint8Array(await data.arrayBuffer()); | ||
const reader = data.stream(); | ||
const writer = createNodeWritableStream(filename, options); | ||
await reader.pipeTo(writer); | ||
} | ||
else if (typeof ReadableStream === "function" && data instanceof ReadableStream) { | ||
_data = new Uint8Array(await reader.readAsArrayBuffer(data)); | ||
const writer = createNodeWritableStream(filename, options); | ||
await data.pipeTo(writer); | ||
} | ||
else if (data instanceof ArrayBuffer || data instanceof SharedArrayBuffer) { | ||
_data = new Uint8Array(data); | ||
} | ||
else if (typeof data === "string" || "buffer" in data) { | ||
_data = data; | ||
} | ||
else { | ||
throw new Error("Unsupported data type"); | ||
const fs = await import('fs/promises'); | ||
const { append, ...rest } = options; | ||
let _data; | ||
if (data instanceof ArrayBuffer || data instanceof SharedArrayBuffer) { | ||
_data = new Uint8Array(data); | ||
} | ||
else if (typeof data === "string" || "buffer" in data) { | ||
_data = data; | ||
} | ||
else { | ||
throw new TypeError("Unsupported data type"); | ||
} | ||
return await rawOp(fs.writeFile(filename, _data, { | ||
flag: append ? "a" : "w", | ||
...rest, | ||
})); | ||
} | ||
return await rawOp(fs.writeFile(filename, _data, { | ||
flag: (options === null || options === void 0 ? void 0 : options.append) ? "a" : "w", | ||
...rest, | ||
})); | ||
} | ||
@@ -742,10 +708,3 @@ else { | ||
async function writeFileHandle(handle, data, options) { | ||
var _a; | ||
const writer = await rawOp(handle.createWritable({ | ||
keepExistingData: (_a = options === null || options === void 0 ? void 0 : options.append) !== null && _a !== void 0 ? _a : false, | ||
}), "file"); | ||
if (options.append) { | ||
const file = await rawOp(handle.getFile(), "file"); | ||
file.size && writer.seek(file.size); | ||
} | ||
const writer = await createFileHandleWritableStream(handle, options); | ||
if (options.signal) { | ||
@@ -1255,2 +1214,118 @@ const { signal } = options; | ||
} | ||
/** | ||
* Creates a readable stream for the target file. | ||
*/ | ||
function createReadableStream(target, options = {}) { | ||
if (env.isNodeLike) { | ||
if (typeof target === "object") { | ||
throw new TypeError("Expected a file path, got a file handle"); | ||
} | ||
const filename = target; | ||
let reader; | ||
return new ReadableStream({ | ||
async start(controller) { | ||
const fs = await import('fs'); | ||
reader = fs.createReadStream(filename); | ||
reader.on("data", (chunk) => { | ||
const bytes = new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength); | ||
controller.enqueue(bytes); | ||
}); | ||
reader.on("end", () => controller.close()); | ||
reader.on("error", (err) => controller.error(err)); | ||
}, | ||
cancel(reason = undefined) { | ||
reader.destroy(reason); | ||
}, | ||
}); | ||
} | ||
return reader_util.resolveByteStream((async () => { | ||
if (typeof target === "object") { | ||
return await readFileHandleAsStream(target); | ||
} | ||
const filename = target; | ||
if (env.isDeno) { | ||
const file = await rawOp(Deno.open(filename, { read: true })); | ||
return file.readable; | ||
} | ||
else { | ||
const handle = await getFileHandle(filename, { root: options.root }); | ||
return await readFileHandleAsStream(handle); | ||
} | ||
})()); | ||
} | ||
async function readFileHandleAsStream(handle) { | ||
const file = await rawOp(handle.getFile(), "file"); | ||
return file.stream(); | ||
} | ||
/** | ||
* @deprecated use `createReadableStream` instead. | ||
*/ | ||
const readFileAsStream = createReadableStream; | ||
/** | ||
* Creates a writable stream for the target file. | ||
*/ | ||
function createWritableStream(target, options = {}) { | ||
var _a; | ||
if (typeof target === "object") { | ||
const { readable, writable } = new TransformStream(); | ||
createFileHandleWritableStream(target, options) | ||
.then(stream => readable.pipeTo(stream)); | ||
return writable; | ||
} | ||
const filename = target; | ||
if (env.isDeno) { | ||
const { readable, writable } = new TransformStream(); | ||
Deno.open(filename, { write: true, create: true, append: (_a = options.append) !== null && _a !== void 0 ? _a : false }) | ||
.then(file => file.writable) | ||
.then(stream => readable.pipeTo(stream)); | ||
return writable; | ||
} | ||
else if (env.isNodeLike) { | ||
return createNodeWritableStream(filename, options); | ||
} | ||
else { | ||
const { readable, writable } = new TransformStream(); | ||
getFileHandle(filename, { root: options.root, create: true }) | ||
.then(handle => createFileHandleWritableStream(handle, options)) | ||
.then(stream => readable.pipeTo(stream)); | ||
return writable; | ||
} | ||
} | ||
async function createFileHandleWritableStream(handle, options) { | ||
var _a; | ||
const stream = await rawOp(handle.createWritable({ | ||
keepExistingData: (_a = options === null || options === void 0 ? void 0 : options.append) !== null && _a !== void 0 ? _a : false, | ||
}), "file"); | ||
if (options.append) { | ||
const file = await rawOp(handle.getFile(), "file"); | ||
file.size && stream.seek(file.size); | ||
} | ||
return stream; | ||
} | ||
function createNodeWritableStream(filename, options) { | ||
let dest; | ||
return new WritableStream({ | ||
async start() { | ||
const { append, ...rest } = options; | ||
const { createWriteStream } = await import('fs'); | ||
dest = createWriteStream(filename, { | ||
flags: append ? "a" : "w", | ||
...rest, | ||
}); | ||
}, | ||
write(chunk) { | ||
return new Promise((resolve, reject) => { | ||
dest.write(chunk, (err) => err ? reject(err) : resolve()); | ||
}); | ||
}, | ||
close() { | ||
return new Promise((resolve, reject) => { | ||
dest.close((err) => err ? reject(err) : resolve()); | ||
}); | ||
}, | ||
abort(reason) { | ||
dest.destroy(reason); | ||
} | ||
}); | ||
} | ||
@@ -1261,2 +1336,4 @@ exports.EOL = EOL; | ||
exports.copy = copy; | ||
exports.createReadableStream = createReadableStream; | ||
exports.createWritableStream = createWritableStream; | ||
exports.ensureDir = ensureDir; | ||
@@ -1263,0 +1340,0 @@ exports.exists = exists; |
'use strict'; | ||
var filetype = require('../filetype.js'); | ||
var path = require('../path.js'); | ||
function fixFileType(file) { | ||
var _a; | ||
if (!file.type) { | ||
const ext = path.extname(file.name); | ||
if (ext) { | ||
Object.defineProperty(file, "type", { | ||
value: (_a = filetype.getMIME(ext)) !== null && _a !== void 0 ? _a : "", | ||
writable: false, | ||
configurable: true, | ||
}); | ||
} | ||
} | ||
return file; | ||
} | ||
exports.fixFileType = fixFileType; | ||
//# sourceMappingURL=types.js.map |
@@ -29,2 +29,6 @@ 'use strict'; | ||
} | ||
}, | ||
cancel(reason = undefined) { | ||
var _a; | ||
(_a = iterator.throw) === null || _a === void 0 ? void 0 : _a.call(iterator, reason); | ||
} | ||
@@ -31,0 +35,0 @@ }); |
@@ -25,28 +25,5 @@ 'use strict'; | ||
function resolveReadableStream(promise) { | ||
let reader; | ||
return new ReadableStream({ | ||
async start() { | ||
const stream = await promise; | ||
reader = stream.getReader(); | ||
}, | ||
async pull(controller) { | ||
try { | ||
const { done, value } = await reader.read(); | ||
if (done) { | ||
controller.close(); | ||
} | ||
else { | ||
controller.enqueue(value); | ||
} | ||
} | ||
catch (err) { | ||
reader.releaseLock(); | ||
controller.error(err); | ||
} | ||
}, | ||
cancel(reason = undefined) { | ||
reader.cancel(reason); | ||
reader.releaseLock(); | ||
}, | ||
}); | ||
const { readable, writable } = new TransformStream(); | ||
promise.then(stream => stream.pipeTo(writable)); | ||
return readable; | ||
} | ||
@@ -178,2 +155,5 @@ /** | ||
} | ||
catch (err) { | ||
reader.cancel(err); | ||
} | ||
finally { | ||
@@ -180,0 +160,0 @@ reader.releaseLock(); |
@@ -171,5 +171,5 @@ /** | ||
// copy listeners in cased being modified | ||
const listeners = [...stdin.listeners("data")]; | ||
const listeners = [...stdin.listeners("data")] as ((chunk: Buffer) => void)[]; | ||
if (listeners?.length) { | ||
if (listeners.length) { | ||
stdin.removeAllListeners("data"); | ||
@@ -184,4 +184,4 @@ } | ||
if (listeners?.length) { | ||
listeners.forEach(listener => stdin.addListener("data", listener as any)); | ||
if (listeners.length) { | ||
listeners.forEach(listener => stdin.addListener("data", listener)); | ||
} else { | ||
@@ -188,0 +188,0 @@ stdin.pause(); |
@@ -172,3 +172,3 @@ /** | ||
try { | ||
const res = handler.call(this as any, _data) as any; | ||
const res = handler.call(this, _data) as any; | ||
@@ -175,0 +175,0 @@ if (typeof res?.then === "function") { |
@@ -1,7 +0,5 @@ | ||
import { basename, join } from "../path.ts"; | ||
import { isBrowserWindow, isDeno, isNodeLike } from "../env.ts"; | ||
import { platform } from "../runtime.ts"; | ||
import { isWSL, which } from "../cli.ts"; | ||
import { readAsObjectURL, toAsyncIterable } from "../reader.ts"; | ||
import { readFile } from "./terminal/util.ts"; | ||
import { readAsObjectURL } from "../reader.ts"; | ||
import { | ||
@@ -28,3 +26,4 @@ macPickFolder, | ||
import { getExtensions } from "../filetype.ts"; | ||
import { writeFile } from "../fs.ts"; | ||
import { readDir, readFileAsFile, writeFile } from "../fs.ts"; | ||
import { fixFileType } from "../fs/types.ts"; | ||
import { as } from "../object.ts"; | ||
@@ -178,24 +177,16 @@ | ||
await (async function walk(dir: FileSystemDirectoryHandle, base = "") { | ||
const entries = (dir as any).entries() as AsyncIterable<[string, FileSystemHandle]>; | ||
for await (const entry of readDir(dir, { recursive: true })) { | ||
if (entry.kind === "file") { | ||
const file = await (entry.handle as FileSystemFileHandle).getFile(); | ||
for await (const [_, entry] of entries) { | ||
const path = join(base, entry.name); | ||
Object.defineProperty(file, "webkitRelativePath", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: false, | ||
value: entry.path ?? "", | ||
}); | ||
if (entry.kind === "file") { | ||
const file = await (entry as FileSystemFileHandle).getFile(); | ||
Object.defineProperty(file, "webkitRelativePath", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: false, | ||
value: path ?? "", | ||
}); | ||
files.push(file); | ||
} else { | ||
await walk(entry as FileSystemDirectoryHandle, path); | ||
} | ||
files.push(fixFileType(file)); | ||
} | ||
})(dir); | ||
} | ||
@@ -210,3 +201,3 @@ return files; | ||
const file = await handle.getFile(); | ||
files.push(file); | ||
files.push(fixFileType(file)); | ||
} | ||
@@ -217,3 +208,3 @@ | ||
const handle = await browserPickFile(type); | ||
return handle ? await handle.getFile() : null; | ||
return handle ? await handle.getFile().then(fixFileType) : null; | ||
} | ||
@@ -265,50 +256,24 @@ } else if (isBrowserWindow) { | ||
if (dirname) { | ||
const folder = basename(dirname); | ||
const files: { path: string, relativePath: string; }[] = []; | ||
const files: File[] = []; | ||
if (typeof Deno === "object") { | ||
await (async function walk(dirname: string, relativePath = "") { | ||
for await (const entry of Deno.readDir(dirname)) { | ||
if (entry.isFile) { | ||
files.push({ | ||
path: join(dirname, entry.name), | ||
relativePath: relativePath + "/" + entry.name, | ||
}); | ||
} else if (entry.isDirectory) { | ||
await walk(join(dirname, entry.name), relativePath + "/" + entry.name); | ||
} else if (entry.isSymlink) { | ||
const symlink = await Deno.readLink(join(dirname, entry.name)); | ||
await walk(symlink, relativePath + "/" + entry.name); | ||
} | ||
} | ||
})(dirname, folder); | ||
} else { | ||
const { readdir, readlink } = await import("fs/promises"); | ||
for await (const entry of readDir(dirname, { recursive: true })) { | ||
if (entry.kind === "file") { | ||
const file = await (entry.handle as FileSystemFileHandle).getFile(); | ||
await (async function walk(dirname: string, relativePath = "") { | ||
const entries = await readdir(dirname, { withFileTypes: true }); | ||
Object.defineProperty(file, "webkitRelativePath", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: false, | ||
value: entry.path ?? "", | ||
}); | ||
for (const entry of entries) { | ||
if (entry.isFile()) { | ||
files.push({ | ||
path: join(dirname, entry.name), | ||
relativePath: relativePath + "/" + entry.name, | ||
}); | ||
} else if (entry.isDirectory()) { | ||
await walk(join(dirname, entry.name), relativePath + "/" + entry.name); | ||
} else if (entry.isSymbolicLink()) { | ||
const symlink = await readlink(join(dirname, entry.name)); | ||
await walk(symlink, relativePath + "/" + entry.name); | ||
} | ||
} | ||
})(dirname, folder); | ||
files.push(fixFileType(file)); | ||
} | ||
} | ||
return await Promise.all(files.map(({ path, relativePath }) => { | ||
return readFile(path, relativePath); | ||
})); | ||
return files; | ||
} else if (filenames) { | ||
return await Promise.all(filenames.map(path => readFile(path))); | ||
return await Promise.all(filenames.map(path => readFileAsFile(path))); | ||
} else if (filename) { | ||
return await readFile(filename); | ||
return await readFileAsFile(filename); | ||
} else if (directory || multiple) { | ||
@@ -358,3 +323,3 @@ return []; | ||
forSave: true, | ||
defaultName: options.name || as(file, Blob)?.name, | ||
defaultName: options.name || as(file, File)?.name, | ||
}); | ||
@@ -399,33 +364,12 @@ | ||
const { title } = options; | ||
let stream: ReadableStream<Uint8Array> | undefined; | ||
let filename: string | null | undefined; | ||
if (typeof ReadableStream === "function" && file instanceof ReadableStream) { | ||
stream = file; | ||
if (typeof Blob === "function" && file instanceof Blob) { | ||
filename = await pickFile({ | ||
title, | ||
type: options.type, | ||
forSave: true, | ||
defaultName: options.name, | ||
}) as string | null; | ||
} else if (typeof File === "function" && file instanceof File) { | ||
stream = file.stream(); | ||
filename = await pickFile({ | ||
title, | ||
type: file.type, | ||
forSave: true, | ||
defaultName: options.name || file.name, | ||
}) as string | null; | ||
} else if (typeof Blob === "function" && file instanceof Blob) { | ||
stream = file.stream(); | ||
filename = await pickFile({ | ||
title, | ||
type: options.type || file.type, | ||
forSave: true, | ||
defaultName: options.name, | ||
defaultName: options.name || as(file, File)?.name, | ||
}) as string | null; | ||
} else { | ||
const type = options.type || "application/octet-stream"; | ||
const blob = new Blob([file as Uint8Array | ArrayBuffer], { type }); | ||
stream = blob.stream(); | ||
filename = await pickFile({ | ||
@@ -440,14 +384,3 @@ title, | ||
if (filename) { | ||
if (typeof Deno === "object") { | ||
await Deno.writeFile(filename, stream, { create: true }); | ||
} else { | ||
const { createWriteStream } = await import("fs"); | ||
const out = createWriteStream(filename, { flags: "w" }); | ||
for await (const chunk of toAsyncIterable(stream)) { | ||
out.write(chunk); | ||
} | ||
out.close(); | ||
} | ||
await writeFile(filename, file); | ||
} | ||
@@ -454,0 +387,0 @@ } else { |
@@ -1,49 +0,3 @@ | ||
import { basename, extname } from "../../path.ts"; | ||
import { getMIME } from "../../filetype.ts"; | ||
export function escape(str: string) { | ||
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); | ||
} | ||
export function createFileObject(content: Uint8Array, path: string, options: { | ||
lastModified?: number; | ||
relativePath?: string; | ||
}): File { | ||
const { lastModified, relativePath } = options; | ||
const filename = basename(path); | ||
const type = getMIME(extname(filename)) ?? ""; | ||
let file: File; | ||
if (lastModified) { | ||
file = new File([content], filename, { type, lastModified }); | ||
} else { | ||
file = new File([content], path, { type }); | ||
} | ||
Object.defineProperty(file, "webkitRelativePath", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: false, | ||
value: relativePath ?? "", | ||
}); | ||
return file; | ||
} | ||
export async function readFile(path: string, relativePath = ""): Promise<File> { | ||
let content: Uint8Array; | ||
let lastModified: number; | ||
if (typeof Deno === "object") { | ||
const stats = await Deno.stat(path); | ||
content = await Deno.readFile(path); | ||
lastModified = stats.mtime ? stats.mtime.valueOf() : 0; | ||
} else { | ||
const { readFile, stat } = await import("fs/promises"); | ||
const stats = await stat(path); | ||
content = await readFile(path); | ||
lastModified = stats.mtimeMs; | ||
} | ||
return createFileObject(content, path, { relativePath, lastModified }); | ||
} |
@@ -22,3 +22,3 @@ export const id = Symbol.for("id"); | ||
export const isBun = typeof Bun === "object" && !!Bun.version; | ||
export const isNodeLike = typeof process === "object" && !!process.versions?.node; | ||
export const isNodeLike = typeof process === "object" && !!process.versions?.node && !isDeno; | ||
export const isNode: boolean = isNodeLike && !isDeno && !isBun; | ||
@@ -25,0 +25,0 @@ |
@@ -158,3 +158,3 @@ import { isWide, isFullWidth } from '../external/code-point-utils/index.js'; | ||
const listeners = [...stdin.listeners("data")]; | ||
if (listeners === null || listeners === void 0 ? void 0 : listeners.length) { | ||
if (listeners.length) { | ||
stdin.removeAllListeners("data"); | ||
@@ -168,3 +168,3 @@ } | ||
stdin.setRawMode(false); | ||
if (listeners === null || listeners === void 0 ? void 0 : listeners.length) { | ||
if (listeners.length) { | ||
listeners.forEach(listener => stdin.addListener("data", listener)); | ||
@@ -171,0 +171,0 @@ } |
@@ -1,2 +0,1 @@ | ||
import { join, basename } from '../path.js'; | ||
import { isBrowserWindow, isDeno, isNodeLike } from '../env.js'; | ||
@@ -6,3 +5,2 @@ import { platform } from '../runtime.js'; | ||
import { readAsObjectURL } from '../reader.js'; | ||
import { readFile } from './terminal/util.js'; | ||
import { macPickFile, macPickFiles, macPickFolder } from './terminal/file/mac.js'; | ||
@@ -13,5 +11,5 @@ import { linuxPickFile, linuxPickFiles, linuxPickFolder } from './terminal/file/linux.js'; | ||
import { getExtensions } from '../filetype.js'; | ||
import { writeFile } from '../fs.js'; | ||
import { readDir, readFileAsFile, writeFile } from '../fs.js'; | ||
import { fixFileType } from '../fs/types.js'; | ||
import { as } from '../object.js'; | ||
import { toAsyncIterable } from '../reader/util.js'; | ||
import { isWSL } from '../cli/common.js'; | ||
@@ -105,2 +103,3 @@ | ||
async function openFile(options = {}) { | ||
var _a, _b; | ||
const { title = "", type = "", multiple = false, directory = false } = options; | ||
@@ -113,21 +112,14 @@ if (directory && typeof globalThis["showDirectoryPicker"] === "function") { | ||
} | ||
await (async function walk(dir, base = "") { | ||
const entries = dir.entries(); | ||
for await (const [_, entry] of entries) { | ||
const path = join(base, entry.name); | ||
if (entry.kind === "file") { | ||
const file = await entry.getFile(); | ||
Object.defineProperty(file, "webkitRelativePath", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: false, | ||
value: path !== null && path !== void 0 ? path : "", | ||
}); | ||
files.push(file); | ||
} | ||
else { | ||
await walk(entry, path); | ||
} | ||
for await (const entry of readDir(dir, { recursive: true })) { | ||
if (entry.kind === "file") { | ||
const file = await entry.handle.getFile(); | ||
Object.defineProperty(file, "webkitRelativePath", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: false, | ||
value: (_a = entry.path) !== null && _a !== void 0 ? _a : "", | ||
}); | ||
files.push(fixFileType(file)); | ||
} | ||
})(dir); | ||
} | ||
return files; | ||
@@ -141,3 +133,3 @@ } | ||
const file = await handle.getFile(); | ||
files.push(file); | ||
files.push(fixFileType(file)); | ||
} | ||
@@ -148,3 +140,3 @@ return files; | ||
const handle = await browserPickFile(type); | ||
return handle ? await handle.getFile() : null; | ||
return handle ? await handle.getFile().then(fixFileType) : null; | ||
} | ||
@@ -199,53 +191,22 @@ } | ||
if (dirname) { | ||
const folder = basename(dirname); | ||
const files = []; | ||
if (typeof Deno === "object") { | ||
await (async function walk(dirname, relativePath = "") { | ||
for await (const entry of Deno.readDir(dirname)) { | ||
if (entry.isFile) { | ||
files.push({ | ||
path: join(dirname, entry.name), | ||
relativePath: relativePath + "/" + entry.name, | ||
}); | ||
} | ||
else if (entry.isDirectory) { | ||
await walk(join(dirname, entry.name), relativePath + "/" + entry.name); | ||
} | ||
else if (entry.isSymlink) { | ||
const symlink = await Deno.readLink(join(dirname, entry.name)); | ||
await walk(symlink, relativePath + "/" + entry.name); | ||
} | ||
} | ||
})(dirname, folder); | ||
for await (const entry of readDir(dirname, { recursive: true })) { | ||
if (entry.kind === "file") { | ||
const file = await entry.handle.getFile(); | ||
Object.defineProperty(file, "webkitRelativePath", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: false, | ||
value: (_b = entry.path) !== null && _b !== void 0 ? _b : "", | ||
}); | ||
files.push(fixFileType(file)); | ||
} | ||
} | ||
else { | ||
const { readdir, readlink } = await import('fs/promises'); | ||
await (async function walk(dirname, relativePath = "") { | ||
const entries = await readdir(dirname, { withFileTypes: true }); | ||
for (const entry of entries) { | ||
if (entry.isFile()) { | ||
files.push({ | ||
path: join(dirname, entry.name), | ||
relativePath: relativePath + "/" + entry.name, | ||
}); | ||
} | ||
else if (entry.isDirectory()) { | ||
await walk(join(dirname, entry.name), relativePath + "/" + entry.name); | ||
} | ||
else if (entry.isSymbolicLink()) { | ||
const symlink = await readlink(join(dirname, entry.name)); | ||
await walk(symlink, relativePath + "/" + entry.name); | ||
} | ||
} | ||
})(dirname, folder); | ||
} | ||
return await Promise.all(files.map(({ path, relativePath }) => { | ||
return readFile(path, relativePath); | ||
})); | ||
return files; | ||
} | ||
else if (filenames) { | ||
return await Promise.all(filenames.map(path => readFile(path))); | ||
return await Promise.all(filenames.map(path => readFileAsFile(path))); | ||
} | ||
else if (filename) { | ||
return await readFile(filename); | ||
return await readFileAsFile(filename); | ||
} | ||
@@ -264,3 +225,3 @@ else if (directory || multiple) { | ||
async function saveFile(file, options = {}) { | ||
var _a; | ||
var _a, _b; | ||
if (typeof globalThis["showSaveFilePicker"] === "function") { | ||
@@ -270,3 +231,3 @@ try { | ||
forSave: true, | ||
defaultName: options.name || ((_a = as(file, Blob)) === null || _a === void 0 ? void 0 : _a.name), | ||
defaultName: options.name || ((_a = as(file, File)) === null || _a === void 0 ? void 0 : _a.name), | ||
}); | ||
@@ -311,35 +272,12 @@ if (handle) { | ||
const { title } = options; | ||
let stream; | ||
let filename; | ||
if (typeof ReadableStream === "function" && file instanceof ReadableStream) { | ||
stream = file; | ||
if (typeof Blob === "function" && file instanceof Blob) { | ||
filename = await pickFile({ | ||
title, | ||
type: options.type, | ||
forSave: true, | ||
defaultName: options.name, | ||
}); | ||
} | ||
else if (typeof File === "function" && file instanceof File) { | ||
stream = file.stream(); | ||
filename = await pickFile({ | ||
title, | ||
type: file.type, | ||
forSave: true, | ||
defaultName: options.name || file.name, | ||
}); | ||
} | ||
else if (typeof Blob === "function" && file instanceof Blob) { | ||
stream = file.stream(); | ||
filename = await pickFile({ | ||
title, | ||
type: options.type || file.type, | ||
forSave: true, | ||
defaultName: options.name, | ||
defaultName: options.name || ((_b = as(file, File)) === null || _b === void 0 ? void 0 : _b.name), | ||
}); | ||
} | ||
else { | ||
const type = options.type || "application/octet-stream"; | ||
const blob = new Blob([file], { type }); | ||
stream = blob.stream(); | ||
filename = await pickFile({ | ||
@@ -353,13 +291,3 @@ title, | ||
if (filename) { | ||
if (typeof Deno === "object") { | ||
await Deno.writeFile(filename, stream, { create: true }); | ||
} | ||
else { | ||
const { createWriteStream } = await import('fs'); | ||
const out = createWriteStream(filename, { flags: "w" }); | ||
for await (const chunk of toAsyncIterable(stream)) { | ||
out.write(chunk); | ||
} | ||
out.close(); | ||
} | ||
await writeFile(filename, file); | ||
} | ||
@@ -366,0 +294,0 @@ } |
@@ -1,45 +0,6 @@ | ||
import { basename, extname } from '../../path.js'; | ||
import { getMIME } from '../../filetype.js'; | ||
function escape(str) { | ||
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); | ||
} | ||
function createFileObject(content, path, options) { | ||
var _a; | ||
const { lastModified, relativePath } = options; | ||
const filename = basename(path); | ||
const type = (_a = getMIME(extname(filename))) !== null && _a !== void 0 ? _a : ""; | ||
let file; | ||
if (lastModified) { | ||
file = new File([content], filename, { type, lastModified }); | ||
} | ||
else { | ||
file = new File([content], path, { type }); | ||
} | ||
Object.defineProperty(file, "webkitRelativePath", { | ||
configurable: true, | ||
enumerable: true, | ||
writable: false, | ||
value: relativePath !== null && relativePath !== void 0 ? relativePath : "", | ||
}); | ||
return file; | ||
} | ||
async function readFile(path, relativePath = "") { | ||
let content; | ||
let lastModified; | ||
if (typeof Deno === "object") { | ||
const stats = await Deno.stat(path); | ||
content = await Deno.readFile(path); | ||
lastModified = stats.mtime ? stats.mtime.valueOf() : 0; | ||
} | ||
else { | ||
const { readFile, stat } = await import('fs/promises'); | ||
const stats = await stat(path); | ||
content = await readFile(path); | ||
lastModified = stats.mtimeMs; | ||
} | ||
return createFileObject(content, path, { relativePath, lastModified }); | ||
} | ||
export { createFileObject, escape, readFile }; | ||
export { escape }; | ||
//# sourceMappingURL=util.js.map |
@@ -15,3 +15,3 @@ var _a, _b; | ||
const isBun = typeof Bun === "object" && !!Bun.version; | ||
const isNodeLike = typeof process === "object" && !!((_b = process.versions) === null || _b === void 0 ? void 0 : _b.node); | ||
const isNodeLike = typeof process === "object" && !!((_b = process.versions) === null || _b === void 0 ? void 0 : _b.node) && !isDeno; | ||
const isNode = isNodeLike && !isDeno && !isBun; | ||
@@ -18,0 +18,0 @@ const isNodeBelow14 = isNode && parseInt(process.version.slice(1)) < 14; |
209
esm/fs.js
@@ -8,4 +8,5 @@ import { orderBy, startsWith } from './array.js'; | ||
import { getMIME } from './filetype.js'; | ||
import { fixFileType } from './fs/types.js'; | ||
import { dirname, basename, extname, join } from './path.js'; | ||
import { readAsArray, toReadableStream, readAsArrayBuffer } from './reader.js'; | ||
import { readAsArray } from './reader.js'; | ||
import { platform } from './runtime.js'; | ||
@@ -643,46 +644,6 @@ import { stripStart } from './string.js'; | ||
async function readFileHandleAsFile(handle) { | ||
var _a; | ||
const file = await rawOp(handle.getFile(), "file"); | ||
if (!file.type) { | ||
const ext = extname(file.name); | ||
if (ext) { | ||
Object.defineProperty(file, "type", { | ||
value: (_a = getMIME(ext)) !== null && _a !== void 0 ? _a : "", | ||
writable: false, | ||
configurable: true, | ||
}); | ||
} | ||
} | ||
return file; | ||
return fixFileType(file); | ||
} | ||
/** | ||
* Reads the file as a `ReadableStream`. | ||
*/ | ||
function readFileAsStream(target, options = {}) { | ||
return resolveByteStream((async () => { | ||
if (typeof target === "object") { | ||
return await readFileHandleAsStream(target); | ||
} | ||
const filename = target; | ||
if (isDeno) { | ||
const file = await rawOp(Deno.open(filename, { read: true })); | ||
return file.readable; | ||
} | ||
else if (isNodeLike) { | ||
const filename = target; | ||
const fs = await import('fs'); | ||
const reader = fs.createReadStream(filename); | ||
return toReadableStream(reader); | ||
} | ||
else { | ||
const handle = await getFileHandle(filename, { root: options.root }); | ||
return await readFileHandleAsStream(handle); | ||
} | ||
})()); | ||
} | ||
async function readFileHandleAsStream(handle) { | ||
const file = await rawOp(handle.getFile(), "file"); | ||
return file.stream(); | ||
} | ||
/** | ||
* Writes the given data to the file. | ||
@@ -710,24 +671,29 @@ */ | ||
else if (isNodeLike) { | ||
const fs = await import('fs/promises'); | ||
const { append, ...rest } = options; | ||
let _data; | ||
if (typeof Blob === "function" && data instanceof Blob) { | ||
_data = new Uint8Array(await data.arrayBuffer()); | ||
const reader = data.stream(); | ||
const writer = createNodeWritableStream(filename, options); | ||
await reader.pipeTo(writer); | ||
} | ||
else if (typeof ReadableStream === "function" && data instanceof ReadableStream) { | ||
_data = new Uint8Array(await readAsArrayBuffer(data)); | ||
const writer = createNodeWritableStream(filename, options); | ||
await data.pipeTo(writer); | ||
} | ||
else if (data instanceof ArrayBuffer || data instanceof SharedArrayBuffer) { | ||
_data = new Uint8Array(data); | ||
} | ||
else if (typeof data === "string" || "buffer" in data) { | ||
_data = data; | ||
} | ||
else { | ||
throw new Error("Unsupported data type"); | ||
const fs = await import('fs/promises'); | ||
const { append, ...rest } = options; | ||
let _data; | ||
if (data instanceof ArrayBuffer || data instanceof SharedArrayBuffer) { | ||
_data = new Uint8Array(data); | ||
} | ||
else if (typeof data === "string" || "buffer" in data) { | ||
_data = data; | ||
} | ||
else { | ||
throw new TypeError("Unsupported data type"); | ||
} | ||
return await rawOp(fs.writeFile(filename, _data, { | ||
flag: append ? "a" : "w", | ||
...rest, | ||
})); | ||
} | ||
return await rawOp(fs.writeFile(filename, _data, { | ||
flag: (options === null || options === void 0 ? void 0 : options.append) ? "a" : "w", | ||
...rest, | ||
})); | ||
} | ||
@@ -740,10 +706,3 @@ else { | ||
async function writeFileHandle(handle, data, options) { | ||
var _a; | ||
const writer = await rawOp(handle.createWritable({ | ||
keepExistingData: (_a = options === null || options === void 0 ? void 0 : options.append) !== null && _a !== void 0 ? _a : false, | ||
}), "file"); | ||
if (options.append) { | ||
const file = await rawOp(handle.getFile(), "file"); | ||
file.size && writer.seek(file.size); | ||
} | ||
const writer = await createFileHandleWritableStream(handle, options); | ||
if (options.signal) { | ||
@@ -1253,4 +1212,120 @@ const { signal } = options; | ||
} | ||
/** | ||
* Creates a readable stream for the target file. | ||
*/ | ||
function createReadableStream(target, options = {}) { | ||
if (isNodeLike) { | ||
if (typeof target === "object") { | ||
throw new TypeError("Expected a file path, got a file handle"); | ||
} | ||
const filename = target; | ||
let reader; | ||
return new ReadableStream({ | ||
async start(controller) { | ||
const fs = await import('fs'); | ||
reader = fs.createReadStream(filename); | ||
reader.on("data", (chunk) => { | ||
const bytes = new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength); | ||
controller.enqueue(bytes); | ||
}); | ||
reader.on("end", () => controller.close()); | ||
reader.on("error", (err) => controller.error(err)); | ||
}, | ||
cancel(reason = undefined) { | ||
reader.destroy(reason); | ||
}, | ||
}); | ||
} | ||
return resolveByteStream((async () => { | ||
if (typeof target === "object") { | ||
return await readFileHandleAsStream(target); | ||
} | ||
const filename = target; | ||
if (isDeno) { | ||
const file = await rawOp(Deno.open(filename, { read: true })); | ||
return file.readable; | ||
} | ||
else { | ||
const handle = await getFileHandle(filename, { root: options.root }); | ||
return await readFileHandleAsStream(handle); | ||
} | ||
})()); | ||
} | ||
async function readFileHandleAsStream(handle) { | ||
const file = await rawOp(handle.getFile(), "file"); | ||
return file.stream(); | ||
} | ||
/** | ||
* @deprecated use `createReadableStream` instead. | ||
*/ | ||
const readFileAsStream = createReadableStream; | ||
/** | ||
* Creates a writable stream for the target file. | ||
*/ | ||
function createWritableStream(target, options = {}) { | ||
var _a; | ||
if (typeof target === "object") { | ||
const { readable, writable } = new TransformStream(); | ||
createFileHandleWritableStream(target, options) | ||
.then(stream => readable.pipeTo(stream)); | ||
return writable; | ||
} | ||
const filename = target; | ||
if (isDeno) { | ||
const { readable, writable } = new TransformStream(); | ||
Deno.open(filename, { write: true, create: true, append: (_a = options.append) !== null && _a !== void 0 ? _a : false }) | ||
.then(file => file.writable) | ||
.then(stream => readable.pipeTo(stream)); | ||
return writable; | ||
} | ||
else if (isNodeLike) { | ||
return createNodeWritableStream(filename, options); | ||
} | ||
else { | ||
const { readable, writable } = new TransformStream(); | ||
getFileHandle(filename, { root: options.root, create: true }) | ||
.then(handle => createFileHandleWritableStream(handle, options)) | ||
.then(stream => readable.pipeTo(stream)); | ||
return writable; | ||
} | ||
} | ||
async function createFileHandleWritableStream(handle, options) { | ||
var _a; | ||
const stream = await rawOp(handle.createWritable({ | ||
keepExistingData: (_a = options === null || options === void 0 ? void 0 : options.append) !== null && _a !== void 0 ? _a : false, | ||
}), "file"); | ||
if (options.append) { | ||
const file = await rawOp(handle.getFile(), "file"); | ||
file.size && stream.seek(file.size); | ||
} | ||
return stream; | ||
} | ||
function createNodeWritableStream(filename, options) { | ||
let dest; | ||
return new WritableStream({ | ||
async start() { | ||
const { append, ...rest } = options; | ||
const { createWriteStream } = await import('fs'); | ||
dest = createWriteStream(filename, { | ||
flags: append ? "a" : "w", | ||
...rest, | ||
}); | ||
}, | ||
write(chunk) { | ||
return new Promise((resolve, reject) => { | ||
dest.write(chunk, (err) => err ? reject(err) : resolve()); | ||
}); | ||
}, | ||
close() { | ||
return new Promise((resolve, reject) => { | ||
dest.close((err) => err ? reject(err) : resolve()); | ||
}); | ||
}, | ||
abort(reason) { | ||
dest.destroy(reason); | ||
} | ||
}); | ||
} | ||
export { EOL, chmod, chown, copy, ensureDir, exists, getDirHandle, getFileHandle, link, mkdir, readDir, readFile, readFileAsFile, readFileAsStream, readFileAsText, readLink, readTree, remove, rename, stat, truncate, utimes, writeFile, writeLines }; | ||
export { EOL, chmod, chown, copy, createReadableStream, createWritableStream, ensureDir, exists, getDirHandle, getFileHandle, link, mkdir, readDir, readFile, readFileAsFile, readFileAsStream, readFileAsText, readLink, readTree, remove, rename, stat, truncate, utimes, writeFile, writeLines }; | ||
//# sourceMappingURL=fs.js.map |
@@ -0,2 +1,20 @@ | ||
import { getMIME } from '../filetype.js'; | ||
import { extname } from '../path.js'; | ||
function fixFileType(file) { | ||
var _a; | ||
if (!file.type) { | ||
const ext = extname(file.name); | ||
if (ext) { | ||
Object.defineProperty(file, "type", { | ||
value: (_a = getMIME(ext)) !== null && _a !== void 0 ? _a : "", | ||
writable: false, | ||
configurable: true, | ||
}); | ||
} | ||
} | ||
return file; | ||
} | ||
export { fixFileType }; | ||
//# sourceMappingURL=types.js.map |
@@ -28,2 +28,6 @@ import { concat, text } from './bytes.js'; | ||
} | ||
}, | ||
cancel(reason = undefined) { | ||
var _a; | ||
(_a = iterator.throw) === null || _a === void 0 ? void 0 : _a.call(iterator, reason); | ||
} | ||
@@ -30,0 +34,0 @@ }); |
@@ -23,28 +23,5 @@ import chan from '../chan.js'; | ||
function resolveReadableStream(promise) { | ||
let reader; | ||
return new ReadableStream({ | ||
async start() { | ||
const stream = await promise; | ||
reader = stream.getReader(); | ||
}, | ||
async pull(controller) { | ||
try { | ||
const { done, value } = await reader.read(); | ||
if (done) { | ||
controller.close(); | ||
} | ||
else { | ||
controller.enqueue(value); | ||
} | ||
} | ||
catch (err) { | ||
reader.releaseLock(); | ||
controller.error(err); | ||
} | ||
}, | ||
cancel(reason = undefined) { | ||
reader.cancel(reason); | ||
reader.releaseLock(); | ||
}, | ||
}); | ||
const { readable, writable } = new TransformStream(); | ||
promise.then(stream => stream.pipeTo(writable)); | ||
return readable; | ||
} | ||
@@ -176,2 +153,5 @@ /** | ||
} | ||
catch (err) { | ||
reader.cancel(err); | ||
} | ||
finally { | ||
@@ -178,0 +158,0 @@ reader.releaseLock(); |
262
fs.ts
@@ -54,11 +54,6 @@ /** | ||
import type { FileInfo, DirEntry, CommonOptions, DirTree } from "./fs/types.ts"; | ||
import { fixFileType } from "./fs/types.ts"; | ||
import { as } from "./object.ts"; | ||
import { basename, dirname, extname, join, split } from "./path.ts"; | ||
import { | ||
readAsArray, | ||
readAsArrayBuffer, | ||
resolveByteStream, | ||
toAsyncIterable, | ||
toReadableStream, | ||
} from "./reader.ts"; | ||
import { readAsArray, resolveByteStream, toAsyncIterable } from "./reader.ts"; | ||
import runtime, { platform } from "./runtime.ts"; | ||
@@ -103,3 +98,3 @@ import { stripStart } from "./string.ts"; | ||
const errName = getErrorName(err); | ||
const errCode = (err as any).code as string | number | undefined; | ||
const errCode = (err as NodeJS.ErrnoException).code; | ||
@@ -735,55 +730,6 @@ if (errName === "NotFoundError" | ||
const file = await rawOp(handle.getFile(), "file"); | ||
if (!file.type) { | ||
const ext = extname(file.name); | ||
if (ext) { | ||
Object.defineProperty(file, "type", { | ||
value: getMIME(ext) ?? "", | ||
writable: false, | ||
configurable: true, | ||
}); | ||
} | ||
} | ||
return file; | ||
return fixFileType(file); | ||
} | ||
/** | ||
* Reads the file as a `ReadableStream`. | ||
*/ | ||
export function readFileAsStream( | ||
target: string | FileSystemFileHandle, | ||
options: CommonOptions = {} | ||
): ReadableStream<Uint8Array> { | ||
return resolveByteStream((async () => { | ||
if (typeof target === "object") { | ||
return await readFileHandleAsStream(target); | ||
} | ||
const filename = target; | ||
if (isDeno) { | ||
const file = await rawOp(Deno.open(filename, { read: true })); | ||
return file.readable; | ||
} else if (isNodeLike) { | ||
const filename = target as string; | ||
const fs = await import("fs"); | ||
const reader = fs.createReadStream(filename); | ||
return toReadableStream<Uint8Array>(reader); | ||
} else { | ||
const handle = await getFileHandle(filename, { root: options.root }); | ||
return await readFileHandleAsStream(handle); | ||
} | ||
})()); | ||
} | ||
async function readFileHandleAsStream( | ||
handle: FileSystemFileHandle | ||
): Promise<ReadableStream<Uint8Array>> { | ||
const file = await rawOp(handle.getFile(), "file"); | ||
return file.stream(); | ||
} | ||
/** | ||
* Writes the given data to the file. | ||
@@ -823,25 +769,30 @@ */ | ||
} else { | ||
return await rawOp(Deno.writeFile(filename, data as any, options)); | ||
return await rawOp(Deno.writeFile(filename, data, options)); | ||
} | ||
} else if (isNodeLike) { | ||
const fs = await import("fs/promises"); | ||
const { append, ...rest } = options; | ||
let _data: Uint8Array | string; | ||
if (typeof Blob === "function" && data instanceof Blob) { | ||
_data = new Uint8Array(await data.arrayBuffer()); | ||
const reader = data.stream(); | ||
const writer = createNodeWritableStream(filename, options); | ||
await reader.pipeTo(writer); | ||
} else if (typeof ReadableStream === "function" && data instanceof ReadableStream) { | ||
_data = new Uint8Array(await readAsArrayBuffer(data)); | ||
} else if (data instanceof ArrayBuffer || data instanceof SharedArrayBuffer) { | ||
_data = new Uint8Array(data); | ||
} else if (typeof data === "string" || "buffer" in data) { | ||
_data = data; | ||
const writer = createNodeWritableStream(filename, options); | ||
await data.pipeTo(writer); | ||
} else { | ||
throw new Error("Unsupported data type"); | ||
const fs = await import("fs/promises"); | ||
const { append, ...rest } = options; | ||
let _data: Uint8Array | string; | ||
if (data instanceof ArrayBuffer || data instanceof SharedArrayBuffer) { | ||
_data = new Uint8Array(data); | ||
} else if (typeof data === "string" || "buffer" in data) { | ||
_data = data; | ||
} else { | ||
throw new TypeError("Unsupported data type"); | ||
} | ||
return await rawOp(fs.writeFile(filename, _data, { | ||
flag: append ? "a" : "w", | ||
...rest, | ||
})); | ||
} | ||
return await rawOp(fs.writeFile(filename, _data, { | ||
flag: options?.append ? "a" : "w", | ||
...rest, | ||
})); | ||
} else { | ||
@@ -861,11 +812,4 @@ const handle = await getFileHandle(filename, { root: options.root, create: true }); | ||
): Promise<void> { | ||
const writer = await rawOp(handle.createWritable({ | ||
keepExistingData: options?.append ?? false, | ||
}), "file"); | ||
const writer = await createFileHandleWritableStream(handle, options); | ||
if (options.append) { | ||
const file = await rawOp(handle.getFile(), "file"); | ||
file.size && writer.seek(file.size); | ||
} | ||
if (options.signal) { | ||
@@ -1458,1 +1402,153 @@ const { signal } = options; | ||
} | ||
/** | ||
* Creates a readable stream for the target file. | ||
*/ | ||
export function createReadableStream( | ||
target: string | FileSystemFileHandle, | ||
options: CommonOptions = {} | ||
): ReadableStream<Uint8Array> { | ||
if (isNodeLike) { | ||
if (typeof target === "object") { | ||
throw new TypeError("Expected a file path, got a file handle"); | ||
} | ||
const filename = target as string; | ||
let reader: import("fs").ReadStream; | ||
return new ReadableStream<Uint8Array>({ | ||
async start(controller) { | ||
const fs = await import("fs"); | ||
reader = fs.createReadStream(filename); | ||
reader.on("data", (chunk: Buffer) => { | ||
const bytes = new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength); | ||
controller.enqueue(bytes); | ||
}); | ||
reader.on("end", () => controller.close()); | ||
reader.on("error", (err: Error) => controller.error(err)); | ||
}, | ||
cancel(reason = undefined) { | ||
reader.destroy(reason); | ||
}, | ||
}); | ||
} | ||
return resolveByteStream((async () => { | ||
if (typeof target === "object") { | ||
return await readFileHandleAsStream(target); | ||
} | ||
const filename = target; | ||
if (isDeno) { | ||
const file = await rawOp(Deno.open(filename, { read: true })); | ||
return file.readable; | ||
} else { | ||
const handle = await getFileHandle(filename, { root: options.root }); | ||
return await readFileHandleAsStream(handle); | ||
} | ||
})()); | ||
} | ||
async function readFileHandleAsStream( | ||
handle: FileSystemFileHandle | ||
): Promise<ReadableStream<Uint8Array>> { | ||
const file = await rawOp(handle.getFile(), "file"); | ||
return file.stream(); | ||
} | ||
/** | ||
* @deprecated use `createReadableStream` instead. | ||
*/ | ||
export const readFileAsStream = createReadableStream; | ||
/** | ||
* Creates a writable stream for the target file. | ||
*/ | ||
export function createWritableStream( | ||
target: string | FileSystemFileHandle, | ||
options: CommonOptions & { | ||
/** | ||
* Append the data to the file instead of overwriting it. | ||
*/ | ||
append?: boolean; | ||
/** | ||
* Permissions always applied to file. | ||
* | ||
* NOTE: This option is ignored in the browser. | ||
* @default 0o666 | ||
*/ | ||
mode?: number; | ||
} = {} | ||
): WritableStream<Uint8Array> { | ||
if (typeof target === "object") { | ||
const { readable, writable } = new TransformStream(); | ||
createFileHandleWritableStream(target, options) | ||
.then(stream => readable.pipeTo(stream)); | ||
return writable; | ||
} | ||
const filename = target; | ||
if (isDeno) { | ||
const { readable, writable } = new TransformStream(); | ||
Deno.open(filename, { write: true, create: true, append: options.append ?? false }) | ||
.then(file => file.writable) | ||
.then(stream => readable.pipeTo(stream)); | ||
return writable; | ||
} else if (isNodeLike) { | ||
return createNodeWritableStream(filename, options); | ||
} else { | ||
const { readable, writable } = new TransformStream(); | ||
getFileHandle(filename, { root: options.root, create: true }) | ||
.then(handle => createFileHandleWritableStream(handle, options)) | ||
.then(stream => readable.pipeTo(stream)); | ||
return writable; | ||
} | ||
} | ||
async function createFileHandleWritableStream(handle: FileSystemFileHandle, options: { | ||
append?: boolean; | ||
}): Promise<FileSystemWritableFileStream> { | ||
const stream = await rawOp(handle.createWritable({ | ||
keepExistingData: options?.append ?? false, | ||
}), "file"); | ||
if (options.append) { | ||
const file = await rawOp(handle.getFile(), "file"); | ||
file.size && stream.seek(file.size); | ||
} | ||
return stream; | ||
} | ||
function createNodeWritableStream(filename: string, options: { | ||
append?: boolean; | ||
mode?: number; | ||
}): WritableStream<Uint8Array> { | ||
let dest: import("fs").WriteStream; | ||
return new WritableStream<Uint8Array>({ | ||
async start() { | ||
const { append, ...rest } = options; | ||
const { createWriteStream } = await import("fs"); | ||
dest = createWriteStream(filename, { | ||
flags: append ? "a" : "w", | ||
...rest, | ||
}); | ||
}, | ||
write(chunk) { | ||
return new Promise<void>((resolve, reject) => { | ||
dest.write(chunk, (err) => err ? reject(err) : resolve()); | ||
}); | ||
}, | ||
close() { | ||
return new Promise((resolve, reject) => { | ||
dest.close((err) => err ? reject(err) : resolve()); | ||
}); | ||
}, | ||
abort(reason) { | ||
dest.destroy(reason); | ||
} | ||
}); | ||
} |
@@ -0,1 +1,4 @@ | ||
import { getMIME } from "../filetype.ts"; | ||
import { extname } from "../path.ts"; | ||
/** | ||
@@ -101,1 +104,17 @@ * Common options for file system operations. | ||
} | ||
export function fixFileType(file: File): File { | ||
if (!file.type) { | ||
const ext = extname(file.name); | ||
if (ext) { | ||
Object.defineProperty(file, "type", { | ||
value: getMIME(ext) ?? "", | ||
writable: false, | ||
configurable: true, | ||
}); | ||
} | ||
} | ||
return file; | ||
} |
{ | ||
"name": "@ayonli/jsext", | ||
"version": "0.9.6", | ||
"version": "0.9.7", | ||
"description": "Additional functions for JavaScript to build strong applications.", | ||
@@ -5,0 +5,0 @@ "exports": { |
@@ -62,2 +62,5 @@ /** | ||
} | ||
}, | ||
cancel(reason = undefined) { | ||
iterator.throw?.(reason); | ||
} | ||
@@ -64,0 +67,0 @@ }); |
@@ -27,27 +27,5 @@ import chan from "../chan.ts"; | ||
export function resolveReadableStream<T>(promise: Promise<ReadableStream<T>>): ReadableStream<T> { | ||
let reader: ReadableStreamDefaultReader<T>; | ||
return new ReadableStream<T>({ | ||
async start() { | ||
const stream = await promise; | ||
reader = stream.getReader(); | ||
}, | ||
async pull(controller) { | ||
try { | ||
const { done, value } = await reader.read(); | ||
if (done) { | ||
controller.close(); | ||
} else { | ||
controller.enqueue(value); | ||
} | ||
} catch (err) { | ||
reader.releaseLock(); | ||
controller.error(err); | ||
} | ||
}, | ||
cancel(reason = undefined) { | ||
reader.cancel(reason); | ||
reader.releaseLock(); | ||
}, | ||
}); | ||
const { readable, writable } = new TransformStream(); | ||
promise.then(stream => stream.pipeTo(writable)); | ||
return readable; | ||
} | ||
@@ -181,2 +159,4 @@ | ||
} | ||
} catch (err) { | ||
reader.cancel(err); | ||
} finally { | ||
@@ -183,0 +163,0 @@ reader.releaseLock(); |
@@ -198,3 +198,3 @@ /** | ||
if (isDeno) { | ||
if (WellknownPlatforms.includes(Deno.build.os as any)) { | ||
if ((WellknownPlatforms as string[]).includes(Deno.build.os)) { | ||
return Deno.build.os as WellknownPlatforms; | ||
@@ -201,0 +201,0 @@ } |
export declare function escape(str: string): string; | ||
export declare function createFileObject(content: Uint8Array, path: string, options: { | ||
lastModified?: number; | ||
relativePath?: string; | ||
}): File; | ||
export declare function readFile(path: string, relativePath?: string): Promise<File>; |
@@ -158,6 +158,2 @@ /** | ||
/** | ||
* Reads the file as a `ReadableStream`. | ||
*/ | ||
export declare function readFileAsStream(target: string | FileSystemFileHandle, options?: CommonOptions): ReadableStream<Uint8Array>; | ||
/** | ||
* Writes the given data to the file. | ||
@@ -298,1 +294,25 @@ */ | ||
export declare function utimes(path: string, atime: number | Date, mtime: number | Date): Promise<void>; | ||
/** | ||
* Creates a readable stream for the target file. | ||
*/ | ||
export declare function createReadableStream(target: string | FileSystemFileHandle, options?: CommonOptions): ReadableStream<Uint8Array>; | ||
/** | ||
* @deprecated use `createReadableStream` instead. | ||
*/ | ||
export declare const readFileAsStream: typeof createReadableStream; | ||
/** | ||
* Creates a writable stream for the target file. | ||
*/ | ||
export declare function createWritableStream(target: string | FileSystemFileHandle, options?: CommonOptions & { | ||
/** | ||
* Append the data to the file instead of overwriting it. | ||
*/ | ||
append?: boolean; | ||
/** | ||
* Permissions always applied to file. | ||
* | ||
* NOTE: This option is ignored in the browser. | ||
* @default 0o666 | ||
*/ | ||
mode?: number; | ||
}): WritableStream<Uint8Array>; |
@@ -98,1 +98,2 @@ /** | ||
} | ||
export declare function fixFileType(file: File): File; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
3280234
46241