end of day

This commit is contained in:
2025-12-30 05:36:35 -08:00
commit 82cacf484c
9 changed files with 255 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
node_modules
dist
+64
View File
@@ -0,0 +1,64 @@
{
"name": "node-file-system-adapter",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"@types/node": "^25.0.3",
"@types/web": "^0.0.310",
"mime": "^4.1.0",
"typescript": "^5.9.3"
}
},
"node_modules/@types/node": {
"version": "25.0.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz",
"integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==",
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
}
},
"node_modules/@types/web": {
"version": "0.0.310",
"resolved": "https://registry.npmjs.org/@types/web/-/web-0.0.310.tgz",
"integrity": "sha512-XN++V7UZGEeRg8MXJBkzMqmcAWoCRN1UV/zpQxg9YnJQ9pIPSuzEG7oidC+nXi/J8pmfb3UgFv+TjEDzMiNnRg==",
"license": "Apache-2.0"
},
"node_modules/mime": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-4.1.0.tgz",
"integrity": "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==",
"funding": [
"https://github.com/sponsors/broofa"
],
"license": "MIT",
"bin": {
"mime": "bin/cli.js"
},
"engines": {
"node": ">=16"
}
},
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"license": "MIT"
}
}
}
+8
View File
@@ -0,0 +1,8 @@
{
"dependencies": {
"@types/node": "^25.0.3",
"@types/web": "^0.0.310",
"mime": "^4.1.0",
"typescript": "^5.9.3"
}
}
+35
View File
@@ -0,0 +1,35 @@
import * as fs from "node:fs";
import * as fsp from "node:fs/promises";
import * as path from "node:path";
import mime from 'mime'
export default class NodeFile implements File {
lastModified: number;
name: string;
webkitRelativePath: string;
size: number;
type: string;
constructor(name: string) {
this.name = path.normalize(name)
const stats = fs.lstatSync(name)
this.lastModified = stats.mtimeMs
this.size = stats.size
this.type = mime.getType(name.split('.').pop())
}
arrayBuffer(): Promise<ArrayBuffer> {
throw new Error("Method not implemented.");
}
bytes(): Promise<Uint8Array<ArrayBuffer>> {
return fsp.readFile(this.name)
}
slice(start?: number, end?: number, contentType?: string): Blob {
throw new Error("Method not implemented.");
}
stream(): ReadableStream<Uint8Array<ArrayBuffer>> {
throw new Error("Method not implemented.");
}
text(): Promise<string> {
return fsp.readFile(this.name,'utf8')
}
}
+63
View File
@@ -0,0 +1,63 @@
import * as fs from 'node:fs';
import * as fsp from 'node:fs/promises';
import * as path from 'node:path';
import NodeFileSystemHandle from './NodeFileSystemHandle';
import NodeFileSystemFileHandle from './NodeFileSystemFileHandle';
export default class NodeFileSystemDirectoryHandle extends NodeFileSystemHandle implements FileSystemDirectoryHandle {
declare kind: "directory";
declare name: string;
constructor(name: string, options?: FileSystemGetDirectoryOptions) {
super()
name=path.normalize(name)
if (!fs.existsSync(name) && options.create) fs.mkdirSync(name)
if (!fs.lstatSync(name).isDirectory()) throw new Error('not a directory')
this.name=name
}
entries(): FileSystemDirectoryHandleAsyncIterator<[string, FileSystemDirectoryHandle | FileSystemFileHandle]> {
const entries: Array<[string, FileSystemDirectoryHandle | FileSystemFileHandle]>=[]
fs.readdirSync(this.name).forEach(name => {
if (fs.lstatSync(name).isDirectory()) {
entries.push([name,new NodeFileSystemDirectoryHandle(path.join(this.name, name))])
} else {
entries.push([name, new NodeFileSystemFileHandle(path.join(this.name, name))])
}
})
return entries[Symbol.asyncIterator]
}
keys(): FileSystemDirectoryHandleAsyncIterator<string> {
return fs.readdirSync(this.name)[Symbol.asyncIterator]
}
values(): FileSystemDirectoryHandleAsyncIterator<FileSystemDirectoryHandle | FileSystemFileHandle> {
const values: Array<FileSystemDirectoryHandle | FileSystemFileHandle> = [];
fs.readdirSync(this.name).forEach(name => {
if (fs.lstatSync(name).isDirectory()) {
values.push(new NodeFileSystemDirectoryHandle(path.join(this.name,name)))
} else {
values.push(new NodeFileSystemFileHandle(path.join(this.name, name)))
}
})
return values[Symbol.asyncIterator]
}
async getDirectoryHandle(name: string, options?: FileSystemGetDirectoryOptions): Promise<FileSystemDirectoryHandle> {
return new NodeFileSystemDirectoryHandle(path.join(this.name, name),options)
}
async getFileHandle(name: string, options?: FileSystemGetFileOptions): Promise<FileSystemFileHandle> {
return new NodeFileSystemFileHandle(path.join(this.name,name),options)
}
removeEntry(name: string, options?: FileSystemRemoveOptions): Promise<void> {
return fsp.rm(name,{'recursive':options.recursive,"force":options.recursive})
}
async resolve(possibleDescendant: FileSystemHandle): Promise<string[] | null> {
if (typeof possibleDescendant !== typeof this) return null
let thisName = this.name
let possibleDescendantName = possibleDescendant.name
if (!path.isAbsolute(this.name)) thisName = path.join(process.cwd(), this.name)
if (!path.isAbsolute(possibleDescendant.name)) possibleDescendantName = path.join(process.cwd(), possibleDescendant.name)
if (!possibleDescendantName.startsWith(thisName)) return null
possibleDescendantName = possibleDescendantName.substring(thisName.length - 1)
if (possibleDescendantName[0] == path.sep) possibleDescendantName = possibleDescendantName.substring(1)
return possibleDescendantName.split(path.sep)
}
[Symbol.asyncIterator]=this.entries
}
+25
View File
@@ -0,0 +1,25 @@
import * as fs from 'node:fs';
import * as fsp from 'node:fs/promises';
import * as path from 'node:path';
import NodeFileSystemHandle from './NodeFileSystemHandle';
import NodeFileSystemWriteableFileStream from './NodeFileSystemWriteableFileStream';
import NodeFile from './NodeFile';
export default class NodeFileSystemFileHandle extends NodeFileSystemHandle implements FileSystemFileHandle {
declare kind: "file";
declare name: string;
constructor(name: string, options?: FileSystemGetFileOptions) {
super()
name=path.normalize(name)
if (!fs.existsSync(name) && options.create) fs.writeFileSync(name,'')
if (fs.lstatSync(name).isDirectory()) new Error('not a file')
this.name=name
}
async createWritable(options?: FileSystemCreateWritableOptions): Promise<FileSystemWritableFileStream> {
return new NodeFileSystemWriteableFileStream(this.name,options)
}
async getFile(): Promise<File> {
return new NodeFile(this.name)
}
}
+14
View File
@@ -0,0 +1,14 @@
import * as path from 'node:path'
export default class NodeFileSystemHandle implements FileSystemHandle {
kind: FileSystemHandleKind;
name: string;
async isSameEntry(other: FileSystemHandle): Promise<boolean> {
if (typeof other != typeof this) return false
let thisName = this.name
let otherName = other.name
if (!path.isAbsolute(this.name)) thisName = path.join(process.cwd(), this.name)
if (!path.isAbsolute(other.name)) otherName = path.join(process.cwd(), other.name)
return thisName === otherName
}
}
+31
View File
@@ -0,0 +1,31 @@
import * as fs from 'node:fs'
import * as fsp from 'node:fs/promises'
export default class NodeFileSystemWriteableFileStream implements FileSystemWritableFileStream {
#name:string
constructor(name: string, options?: FileSystemCreateWritableOptions) {
if (options.keepExistingData) {
}
this.#name=name
}
seek(position: number): Promise<void> {
throw new Error("Method not implemented.");
}
truncate(size: number): Promise<void> {
return fsp.truncate(this.#name,size)
}
async write(data: FileSystemWriteChunkType): Promise<void> {
return fsp.writeFile(this.#name,(data as string))
}
locked: boolean;
abort(reason?: any): Promise<void> {
throw new Error("Method not implemented.");
}
close(): Promise<void> {
throw new Error("Method not implemented.");
}
getWriter(): WritableStreamDefaultWriter<any> {
throw new Error("Method not implemented")
}
}
+13
View File
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "es2022",
"module": "es2022",
"lib": ["ES2022"],
"moduleResolution": "node",
"sourceMap": true,
"declaration": true,
"declarationMap": true,
"outDir": "dist"
},
"include": ["src"]
}