Skip to content

Commit 3542fe5

Browse files
committed
Add --clean flag and throw error instead of overwriting existing packed entry.
- Added the `--clean` command-line flag for unpack operations that will delete the destination directory before unpacking. - Throw an error when packing if an entry with the same `_id` would overwrite an entry that had already been packed as part of the same operation.
1 parent 08669af commit 3542fe5

3 files changed

Lines changed: 34 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 1.0.2
2+
3+
### Improvements
4+
- Added the `--clean` command-line flag for unpack operations that will delete the destination directory before unpacking.
5+
- Throw an error when packing if an entry with the same `_id` would overwrite an entry that had already been packed as part of the same operation.
6+
17
## 1.0.1
28

39
### Fixes

commands/package.mjs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { compilePack, extractPack, TYPE_COLLECTION_MAP } from "../lib/package.mj
2525
* @property {boolean} [nedb] Use NeDB instead of ClassicLevel for database operations.
2626
* @property {boolean} [recursive] When packing, recurse down through all directories in the input
2727
* directory to find source files.
28+
* @property {boolean} [clean] When unpacking, delete the destination directory first.
2829
*/
2930

3031
/**
@@ -107,16 +108,23 @@ export function getCommand() {
107108
type: "boolean"
108109
});
109110

110-
yargs.options("nedb", {
111+
yargs.option("nedb", {
111112
describe: "Whether to use NeDB instead of ClassicLevel for database operations.",
112113
type: "boolean"
113114
});
114115

115-
yargs.options("recursive", {
116+
yargs.option("recursive", {
117+
alias: "r",
116118
describe: "When packing, recurse down through all directories in the input directory to find source files.",
117119
type: "boolean"
118120
});
119121

122+
yargs.option("clean", {
123+
alias: "c",
124+
describe: "When unpacking, delete the destination directory first.",
125+
type: "boolean"
126+
});
127+
120128
return yargs;
121129
},
122130
handler: async argv => {
@@ -366,7 +374,7 @@ async function handleUnpack(argv) {
366374
}
367375

368376
let documentType;
369-
const { nedb, yaml } = argv;
377+
const { nedb, yaml, clean } = argv;
370378
if ( nedb ) {
371379
documentType = determineDocumentType(pack, argv);
372380
if ( !documentType ) {
@@ -386,7 +394,7 @@ async function handleUnpack(argv) {
386394
console.log(`[${dbMode}] Unpacking "${chalk.blue(pack)}" to "${chalk.blue(source)}"`);
387395

388396
try {
389-
await extractPack(pack, source, { nedb, yaml, documentType, log: true });
397+
await extractPack(pack, source, { nedb, yaml, documentType, clean, log: true });
390398
} catch ( err ) {
391399
console.error(err);
392400
process.exitCode = 1;

lib/package.mjs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import { ClassicLevel } from "classic-level";
4444
* @property {object} [yamlOptions] Options to pass to yaml.dump when serializing Documents.
4545
* @property {JSONOptions} [jsonOptions] Options to pass to JSON.stringify when serializing Documents.
4646
* @property {DocumentType} [documentType] Required only for NeDB packs in order to generate a correct key.
47+
* @property {boolean} [clean] Delete the destination directory before unpacking.
4748
* @property {DocumentCollection} [collection] Required only for NeDB packs in order to generate a correct key. Can be
4849
* used instead of documentType if known.
4950
* @property {NameTransformer} [transformName] A function that is used to generate a filename for the extracted
@@ -206,7 +207,14 @@ async function compileNedb(pack, files, { log, transformEntry }={}) {
206207

207208
// Create a new NeDB Datastore.
208209
const db = Datastore.create(pack);
209-
const packDoc = applyHierarchy(doc => delete doc._key);
210+
const seenKeys = new Set();
211+
const packDoc = applyHierarchy(doc => {
212+
if ( seenKeys.has(doc._key) ) {
213+
throw new Error(`An entry with key '${key}' was already packed and would be overwritten by this entry.`);
214+
}
215+
seenKeys.add(doc._key);
216+
delete doc._key;
217+
});
210218

211219
// Iterate over all source files, writing them to the DB.
212220
for ( const file of files ) {
@@ -224,7 +232,7 @@ async function compileNedb(pack, files, { log, transformEntry }={}) {
224232
await db.insert(doc);
225233
if ( log ) console.log(`Packed ${chalk.blue(doc._id)}${chalk.blue(doc.name ? ` (${doc.name})` : "")}`);
226234
} catch ( err ) {
227-
if ( log ) console.error(`Failed to parse ${chalk.red(file)}. See error below.`);
235+
if ( log ) console.error(`Failed to pack ${chalk.red(file)}. See error below.`);
228236
throw err;
229237
}
230238
}
@@ -255,6 +263,9 @@ async function compileClassicLevel(pack, files, { log, transformEntry }={}) {
255263
const packDoc = applyHierarchy(async (doc, collection) => {
256264
const key = doc._key;
257265
delete doc._key;
266+
if ( seenKeys.has(key) ) {
267+
throw new Error(`An entry with key '${key}' was already packed and would be overwritten by this entry.`);
268+
}
258269
seenKeys.add(key);
259270
const value = structuredClone(doc);
260271
await mapHierarchy(value, collection, d => d._id);
@@ -273,7 +284,7 @@ async function compileClassicLevel(pack, files, { log, transformEntry }={}) {
273284
await packDoc(doc, collection);
274285
if ( log ) console.log(`Packed ${chalk.blue(doc._id)}${chalk.blue(doc.name ? ` (${doc.name})` : "")}`);
275286
} catch ( err ) {
276-
if ( log ) console.error(`Failed to parse ${chalk.red(file)}. See error below.`);
287+
if ( log ) console.error(`Failed to pack ${chalk.red(file)}. See error below.`);
277288
throw err;
278289
}
279290
}
@@ -323,7 +334,7 @@ async function compactClassicLevel(db) {
323334
* @returns {Promise<void>}
324335
*/
325336
export async function extractPack(src, dest, {
326-
nedb=false, yaml=false, yamlOptions={}, jsonOptions={}, log=false, documentType, collection, transformEntry,
337+
nedb=false, yaml=false, yamlOptions={}, jsonOptions={}, log=false, documentType, collection, clean, transformEntry,
327338
transformName
328339
}={}) {
329340
if ( nedb && (path.extname(src) !== ".db") ) {
@@ -333,6 +344,7 @@ export async function extractPack(src, dest, {
333344
if ( nedb && !collection ) {
334345
throw new Error("For NeDB operations, a documentType or collection must be provided.");
335346
}
347+
if ( clean ) fs.rmSync(dest, { force: true, recursive: true, maxRetries: 10 });
336348
// Create the output directory if it doesn't exist already.
337349
fs.mkdirSync(dest, { recursive: true });
338350
if ( nedb ) {

0 commit comments

Comments
 (0)