Comparing version 3.0.0 to 3.1.0
@@ -0,5 +1,7 @@ | ||
/// <reference types="node" resolution-mode="require"/> | ||
import { PathLike } from 'node:fs'; | ||
export declare class Writer { | ||
#private; | ||
constructor(filename: string); | ||
constructor(filename: PathLike); | ||
write(data: string): Promise<void>; | ||
} |
123
lib/index.js
@@ -1,13 +0,1 @@ | ||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
if (kind === "m") throw new TypeError("Private method is not writable"); | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); | ||
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; | ||
}; | ||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { | ||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); | ||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); | ||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); | ||
}; | ||
var _Writer_instances, _Writer_filename, _Writer_tempFilename, _Writer_locked, _Writer_prev, _Writer_next, _Writer_nextPromise, _Writer_nextData, _Writer_add, _Writer_write; | ||
import { rename, writeFile } from 'node:fs/promises'; | ||
@@ -18,64 +6,63 @@ import { basename, dirname, join } from 'node:path'; | ||
function getTempFilename(file) { | ||
return join(dirname(file), '.' + basename(file) + '.tmp'); | ||
const f = file.toString(); | ||
return join(dirname(f), `.${basename(f)}.tmp`); | ||
} | ||
export class Writer { | ||
#filename; | ||
#tempFilename; | ||
#locked = false; | ||
#prev = null; | ||
#next = null; | ||
#nextPromise = null; | ||
#nextData = null; | ||
// File is locked, add data for later | ||
#add(data) { | ||
// Only keep most recent data | ||
this.#nextData = data; | ||
// Create a singleton promise to resolve all next promises once next data is written | ||
this.#nextPromise ||= new Promise((resolve, reject) => { | ||
this.#next = [resolve, reject]; | ||
}); | ||
// Return a promise that will resolve at the same time as next promise | ||
return new Promise((resolve, reject) => { | ||
this.#nextPromise?.then(resolve).catch(reject); | ||
}); | ||
} | ||
// File isn't locked, write data | ||
async #write(data) { | ||
// Lock file | ||
this.#locked = true; | ||
try { | ||
// Atomic write | ||
await writeFile(this.#tempFilename, data, 'utf-8'); | ||
await rename(this.#tempFilename, this.#filename); | ||
// Call resolve | ||
this.#prev?.[0](); | ||
} | ||
catch (err) { | ||
// Call reject | ||
if (err instanceof Error) { | ||
this.#prev?.[1](err); | ||
} | ||
throw err; | ||
} | ||
finally { | ||
// Unlock file | ||
this.#locked = false; | ||
this.#prev = this.#next; | ||
this.#next = this.#nextPromise = null; | ||
if (this.#nextData !== null) { | ||
const nextData = this.#nextData; | ||
this.#nextData = null; | ||
await this.write(nextData); | ||
} | ||
} | ||
} | ||
constructor(filename) { | ||
_Writer_instances.add(this); | ||
_Writer_filename.set(this, void 0); | ||
_Writer_tempFilename.set(this, void 0); | ||
_Writer_locked.set(this, false); | ||
_Writer_prev.set(this, null); | ||
_Writer_next.set(this, null); | ||
_Writer_nextPromise.set(this, null); | ||
_Writer_nextData.set(this, null | ||
// File is locked, add data for later | ||
); | ||
__classPrivateFieldSet(this, _Writer_filename, filename, "f"); | ||
__classPrivateFieldSet(this, _Writer_tempFilename, getTempFilename(filename), "f"); | ||
this.#filename = filename; | ||
this.#tempFilename = getTempFilename(filename); | ||
} | ||
async write(data) { | ||
return __classPrivateFieldGet(this, _Writer_locked, "f") ? __classPrivateFieldGet(this, _Writer_instances, "m", _Writer_add).call(this, data) : __classPrivateFieldGet(this, _Writer_instances, "m", _Writer_write).call(this, data); | ||
return this.#locked ? this.#add(data) : this.#write(data); | ||
} | ||
} | ||
_Writer_filename = new WeakMap(), _Writer_tempFilename = new WeakMap(), _Writer_locked = new WeakMap(), _Writer_prev = new WeakMap(), _Writer_next = new WeakMap(), _Writer_nextPromise = new WeakMap(), _Writer_nextData = new WeakMap(), _Writer_instances = new WeakSet(), _Writer_add = function _Writer_add(data) { | ||
// Only keep most recent data | ||
__classPrivateFieldSet(this, _Writer_nextData, data, "f"); | ||
// Create a singleton promise to resolve all next promises once next data is written | ||
__classPrivateFieldSet(this, _Writer_nextPromise, __classPrivateFieldGet(this, _Writer_nextPromise, "f") || new Promise((resolve, reject) => { | ||
__classPrivateFieldSet(this, _Writer_next, [resolve, reject], "f"); | ||
}), "f"); | ||
// Return a promise that will resolve at the same time as next promise | ||
return new Promise((resolve, reject) => { | ||
__classPrivateFieldGet(this, _Writer_nextPromise, "f")?.then(resolve).catch(reject); | ||
}); | ||
}, _Writer_write = | ||
// File isn't locked, write data | ||
async function _Writer_write(data) { | ||
// Lock file | ||
__classPrivateFieldSet(this, _Writer_locked, true, "f"); | ||
try { | ||
// Atomic write | ||
await writeFile(__classPrivateFieldGet(this, _Writer_tempFilename, "f"), data, 'utf-8'); | ||
await rename(__classPrivateFieldGet(this, _Writer_tempFilename, "f"), __classPrivateFieldGet(this, _Writer_filename, "f")); | ||
// Call resolve | ||
__classPrivateFieldGet(this, _Writer_prev, "f")?.[0](); | ||
} | ||
catch (err) { | ||
// Call reject | ||
if (err instanceof Error) { | ||
__classPrivateFieldGet(this, _Writer_prev, "f")?.[1](err); | ||
} | ||
throw err; | ||
} | ||
finally { | ||
// Unlock file | ||
__classPrivateFieldSet(this, _Writer_locked, false, "f"); | ||
__classPrivateFieldSet(this, _Writer_prev, __classPrivateFieldGet(this, _Writer_next, "f"), "f"); | ||
__classPrivateFieldSet(this, _Writer_next, __classPrivateFieldSet(this, _Writer_nextPromise, null, "f"), "f"); | ||
if (__classPrivateFieldGet(this, _Writer_nextData, "f") !== null) { | ||
const nextData = __classPrivateFieldGet(this, _Writer_nextData, "f"); | ||
__classPrivateFieldSet(this, _Writer_nextData, null, "f"); | ||
await this.write(nextData); | ||
} | ||
} | ||
}; |
{ | ||
"name": "steno", | ||
"version": "3.0.0", | ||
"version": "3.1.0", | ||
"description": "Specialized fast async file writer", | ||
@@ -24,3 +24,3 @@ "keywords": [ | ||
"type": "git", | ||
"url": "https://github.com/typicode/steno.git" | ||
"url": "git+https://github.com/typicode/steno.git" | ||
}, | ||
@@ -48,16 +48,16 @@ "funding": "https://github.com/sponsors/typicode", | ||
"devDependencies": { | ||
"@commitlint/cli": "^17.1.2", | ||
"@commitlint/config-conventional": "^17.1.0", | ||
"@commitlint/prompt-cli": "^17.1.2", | ||
"@sindresorhus/tsconfig": "^3.0.1", | ||
"@types/node": "^18.11.0", | ||
"@typicode/eslint-config": "^1.0.0", | ||
"del-cli": "^5.0.0", | ||
"husky": "^8.0.1", | ||
"typescript": "^4.8.4", | ||
"xv": "^1.1.1" | ||
"@commitlint/cli": "^17.7.2", | ||
"@commitlint/config-conventional": "^17.7.0", | ||
"@commitlint/prompt-cli": "^17.7.2", | ||
"@sindresorhus/tsconfig": "^5.0.0", | ||
"@types/node": "^20.8.3", | ||
"@typicode/eslint-config": "^1.2.0", | ||
"del-cli": "^5.1.0", | ||
"husky": "^8.0.3", | ||
"typescript": "^5.2.2", | ||
"xv": "^2.1.1" | ||
}, | ||
"engines": { | ||
"node": ">=14.16" | ||
"node": ">=16" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
6175
74