@nmakarov/cli-toolkit 0.11.4 → 0.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/filedatabase.cjs +195 -15
- package/dist/filedatabase.cjs.map +1 -1
- package/dist/filedatabase.js +192 -14
- package/dist/filedatabase.js.map +1 -1
- package/dist/index.cjs +195 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +193 -13
- package/dist/index.js.map +1 -1
- package/dist/init.cjs +2 -0
- package/dist/init.cjs.map +1 -1
- package/dist/init.js +2 -0
- package/dist/init.js.map +1 -1
- package/dist/mock-server.cjs +168 -13
- package/dist/mock-server.cjs.map +1 -1
- package/dist/mock-server.js +168 -13
- package/dist/mock-server.js.map +1 -1
- package/dist/screen.cjs +2 -0
- package/dist/screen.cjs.map +1 -1
- package/dist/screen.js +2 -0
- package/dist/screen.js.map +1 -1
- package/dist/utils.cjs +251 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.js +199 -0
- package/dist/utils.js.map +1 -0
- package/package.json +6 -1
package/dist/index.js
CHANGED
|
@@ -656,6 +656,8 @@ async function showScreen(config2) {
|
|
|
656
656
|
keyMatches = true;
|
|
657
657
|
} else if (input === binding.key) {
|
|
658
658
|
keyMatches = true;
|
|
659
|
+
} else if (key?.name === binding.key) {
|
|
660
|
+
keyMatches = true;
|
|
659
661
|
}
|
|
660
662
|
if (keyMatches) {
|
|
661
663
|
if (binding.enabled === false) {
|
|
@@ -2502,20 +2504,48 @@ var FileDatabase = class {
|
|
|
2502
2504
|
}
|
|
2503
2505
|
/**
|
|
2504
2506
|
* Figure out what data to write and which file to use (for pagination)
|
|
2507
|
+
* @param data - Data to write
|
|
2508
|
+
* @param targetFileIndex - Optional index of existing file to overwrite (when customMetadata matches)
|
|
2509
|
+
* @param forceNewFile - If true, always create a new file (when customMetadata provided but no match)
|
|
2505
2510
|
*/
|
|
2506
|
-
figureOutDataAndFileToWrite(data) {
|
|
2511
|
+
figureOutDataAndFileToWrite(data, targetFileIndex = null, forceNewFile = false) {
|
|
2507
2512
|
let dataToWrite;
|
|
2508
2513
|
let dataLeftOver;
|
|
2509
2514
|
const incomingDataType = detectDataType(data);
|
|
2510
2515
|
if (this.metadata.dataType !== incomingDataType) {
|
|
2511
2516
|
this.metadata.dataType = incomingDataType;
|
|
2512
2517
|
}
|
|
2513
|
-
if (this.metadata.files.length
|
|
2518
|
+
if (targetFileIndex !== null && targetFileIndex < this.metadata.files.length) {
|
|
2519
|
+
const targetFile = this.metadata.files[targetFileIndex];
|
|
2520
|
+
if (!Array.isArray(data)) {
|
|
2521
|
+
dataToWrite = data;
|
|
2522
|
+
dataLeftOver = null;
|
|
2523
|
+
return { dataToWrite, dataLeftOver, fileName: targetFile.fileName };
|
|
2524
|
+
} else {
|
|
2525
|
+
dataToWrite = data.slice(0, this.pageSize);
|
|
2526
|
+
dataLeftOver = data.slice(this.pageSize);
|
|
2527
|
+
this.lastFileData = dataToWrite;
|
|
2528
|
+
return { dataToWrite, dataLeftOver, fileName: targetFile.fileName };
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
let newlyCreatedFileIndex = null;
|
|
2532
|
+
if (forceNewFile) {
|
|
2533
|
+
const filesBeforeCreate = this.metadata.files.length;
|
|
2534
|
+
this.makeNewFile();
|
|
2535
|
+
newlyCreatedFileIndex = filesBeforeCreate;
|
|
2536
|
+
this.logger.debug?.(`[FileDatabase] Creating new file for unique custom metadata combination, fileNumber: ${this.currentFileNumber}`);
|
|
2537
|
+
} else if (this.metadata.files.length === 0) {
|
|
2514
2538
|
this.makeNewFile();
|
|
2515
2539
|
}
|
|
2516
2540
|
const lastFile = this.metadata.files[this.metadata.files.length - 1];
|
|
2517
2541
|
const lastFileRecordsCount = lastFile.recordsCount;
|
|
2518
|
-
if (
|
|
2542
|
+
if (forceNewFile && newlyCreatedFileIndex !== null) {
|
|
2543
|
+
const newlyCreatedFile = this.metadata.files[newlyCreatedFileIndex];
|
|
2544
|
+
if (newlyCreatedFile && newlyCreatedFile.fileName !== lastFile.fileName) {
|
|
2545
|
+
this.logger.warn?.(`[FileDatabase] Warning: Newly created file ${newlyCreatedFile.fileName} doesn't match last file ${lastFile.fileName}`);
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
if (!Array.isArray(data) && !forceNewFile) {
|
|
2519
2549
|
const lastFileExtension = path3.extname(lastFile.fileName);
|
|
2520
2550
|
const expectedExtension = `.${getFileExtension(incomingDataType)}`;
|
|
2521
2551
|
if (lastFileExtension !== expectedExtension) {
|
|
@@ -2525,24 +2555,35 @@ var FileDatabase = class {
|
|
|
2525
2555
|
lastFile.fileName = `${this.currentFileNumber.toString().padStart(6, "0")}.${getFileExtension(incomingDataType)}`;
|
|
2526
2556
|
}
|
|
2527
2557
|
}
|
|
2558
|
+
} else if (!Array.isArray(data) && forceNewFile) {
|
|
2559
|
+
const lastFileExtension = path3.extname(lastFile.fileName);
|
|
2560
|
+
const expectedExtension = `.${getFileExtension(incomingDataType)}`;
|
|
2561
|
+
if (lastFileExtension !== expectedExtension) {
|
|
2562
|
+
lastFile.fileName = `${this.currentFileNumber.toString().padStart(6, "0")}.${getFileExtension(incomingDataType)}`;
|
|
2563
|
+
}
|
|
2528
2564
|
}
|
|
2529
2565
|
if (Array.isArray(data)) {
|
|
2530
|
-
if (
|
|
2566
|
+
if (forceNewFile) {
|
|
2567
|
+
dataToWrite = data.slice(0, this.pageSize);
|
|
2568
|
+
dataLeftOver = data.slice(this.pageSize);
|
|
2569
|
+
this.lastFileData = dataToWrite;
|
|
2570
|
+
} else if (lastFileRecordsCount < this.pageSize) {
|
|
2531
2571
|
dataToWrite = [...this.lastFileData || [], ...data.slice(0, this.pageSize - lastFileRecordsCount)];
|
|
2532
2572
|
dataLeftOver = data.slice(this.pageSize - lastFileRecordsCount);
|
|
2573
|
+
this.lastFileData = dataToWrite;
|
|
2533
2574
|
} else {
|
|
2534
2575
|
this.makeNewFile();
|
|
2535
2576
|
dataToWrite = data.slice(0, this.pageSize);
|
|
2536
2577
|
dataLeftOver = data.slice(this.pageSize);
|
|
2578
|
+
this.lastFileData = dataToWrite;
|
|
2537
2579
|
}
|
|
2538
|
-
this.lastFileData = dataToWrite;
|
|
2539
2580
|
} else {
|
|
2540
2581
|
dataToWrite = data;
|
|
2541
2582
|
dataLeftOver = null;
|
|
2542
2583
|
}
|
|
2543
2584
|
const fileName = this.metadata.files[this.metadata.files.length - 1].fileName;
|
|
2544
2585
|
this.logger.debug?.(
|
|
2545
|
-
`[FileDatabase] figureOutDataAndFileToWrite: filename=${fileName}, dataToWrite.length=${Array.isArray(dataToWrite) ? dataToWrite.length : "N/A"}, lastFileRecordsCount=${lastFileRecordsCount}`
|
|
2586
|
+
`[FileDatabase] figureOutDataAndFileToWrite: filename=${fileName}, forceNewFile=${forceNewFile}, targetFileIndex=${targetFileIndex}, dataToWrite.length=${Array.isArray(dataToWrite) ? dataToWrite.length : "N/A"}, lastFileRecordsCount=${lastFileRecordsCount}`
|
|
2546
2587
|
);
|
|
2547
2588
|
return { dataToWrite, dataLeftOver, fileName };
|
|
2548
2589
|
}
|
|
@@ -2570,7 +2611,7 @@ var FileDatabase = class {
|
|
|
2570
2611
|
/**
|
|
2571
2612
|
* Update metadata after writing data
|
|
2572
2613
|
*/
|
|
2573
|
-
updateMetadata(dataToWrite, fileName) {
|
|
2614
|
+
updateMetadata(dataToWrite, fileName, customMetadata) {
|
|
2574
2615
|
let currentFile;
|
|
2575
2616
|
if (fileName) {
|
|
2576
2617
|
const foundFile = this.metadata.files.find((file) => file.fileName === fileName);
|
|
@@ -2585,6 +2626,9 @@ var FileDatabase = class {
|
|
|
2585
2626
|
}
|
|
2586
2627
|
const recordsCount = Array.isArray(dataToWrite) ? dataToWrite.length : 1;
|
|
2587
2628
|
currentFile.recordsCount = recordsCount;
|
|
2629
|
+
if (customMetadata) {
|
|
2630
|
+
Object.assign(currentFile, customMetadata);
|
|
2631
|
+
}
|
|
2588
2632
|
const fileIndex = this.metadata.files.indexOf(currentFile);
|
|
2589
2633
|
if (fileIndex !== -1) {
|
|
2590
2634
|
this.calculateFileSynopsis(dataToWrite, fileIndex);
|
|
@@ -2637,6 +2681,11 @@ var FileDatabase = class {
|
|
|
2637
2681
|
} else {
|
|
2638
2682
|
if (!this.metadata.files.length) {
|
|
2639
2683
|
this.metadata = await this.figureMetadata(this.currentVersion);
|
|
2684
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
2685
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
2686
|
+
} else {
|
|
2687
|
+
this.currentFileNumber = 0;
|
|
2688
|
+
}
|
|
2640
2689
|
}
|
|
2641
2690
|
}
|
|
2642
2691
|
} else {
|
|
@@ -2647,16 +2696,22 @@ var FileDatabase = class {
|
|
|
2647
2696
|
try {
|
|
2648
2697
|
const rawData = await fs3.promises.readFile(metadataPath, "utf8");
|
|
2649
2698
|
this.metadata = JSON.parse(rawData);
|
|
2699
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
2700
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
2701
|
+
} else {
|
|
2702
|
+
this.currentFileNumber = 0;
|
|
2703
|
+
}
|
|
2650
2704
|
} catch (e) {
|
|
2651
2705
|
this.metadata = this.getDefaultMetadata();
|
|
2706
|
+
this.currentFileNumber = 0;
|
|
2652
2707
|
}
|
|
2653
2708
|
} else {
|
|
2654
2709
|
this.metadata = this.getDefaultMetadata();
|
|
2655
|
-
this.
|
|
2710
|
+
this.currentFileNumber = 0;
|
|
2656
2711
|
}
|
|
2657
2712
|
} else {
|
|
2658
2713
|
this.metadata = this.getDefaultMetadata();
|
|
2659
|
-
this.
|
|
2714
|
+
this.currentFileNumber = 0;
|
|
2660
2715
|
}
|
|
2661
2716
|
}
|
|
2662
2717
|
} else if (read) {
|
|
@@ -2675,6 +2730,11 @@ var FileDatabase = class {
|
|
|
2675
2730
|
}
|
|
2676
2731
|
if (!this.metadata.files.length) {
|
|
2677
2732
|
this.metadata = await this.figureMetadata(this.currentVersion);
|
|
2733
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
2734
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
2735
|
+
} else {
|
|
2736
|
+
this.currentFileNumber = 0;
|
|
2737
|
+
}
|
|
2678
2738
|
}
|
|
2679
2739
|
} else {
|
|
2680
2740
|
this.currentVersion = null;
|
|
@@ -2688,6 +2748,11 @@ var FileDatabase = class {
|
|
|
2688
2748
|
try {
|
|
2689
2749
|
const rawData = await fs3.promises.readFile(metadataPath, "utf8");
|
|
2690
2750
|
this.metadata = JSON.parse(rawData);
|
|
2751
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
2752
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
2753
|
+
} else {
|
|
2754
|
+
this.currentFileNumber = 0;
|
|
2755
|
+
}
|
|
2691
2756
|
} catch (e) {
|
|
2692
2757
|
throw new FileDatabaseError(`Failed to read metadata: ${e.message}`);
|
|
2693
2758
|
}
|
|
@@ -2696,6 +2761,11 @@ var FileDatabase = class {
|
|
|
2696
2761
|
}
|
|
2697
2762
|
} else {
|
|
2698
2763
|
this.metadata = await this.figureMetadataFromVersionFiles("");
|
|
2764
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
2765
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
2766
|
+
} else {
|
|
2767
|
+
this.currentFileNumber = 0;
|
|
2768
|
+
}
|
|
2699
2769
|
}
|
|
2700
2770
|
}
|
|
2701
2771
|
}
|
|
@@ -2717,14 +2787,44 @@ var FileDatabase = class {
|
|
|
2717
2787
|
this.metadata.dataType = incomingDataType;
|
|
2718
2788
|
this.makeNewFile();
|
|
2719
2789
|
}
|
|
2720
|
-
let
|
|
2790
|
+
let targetFileIndex = null;
|
|
2791
|
+
const hasCustomMetadata = options.customMetadata && Object.keys(options.customMetadata).length > 0;
|
|
2792
|
+
if (hasCustomMetadata) {
|
|
2793
|
+
for (let i = 0; i < this.metadata.files.length; i++) {
|
|
2794
|
+
const fileEntry = this.metadata.files[i];
|
|
2795
|
+
const matches = Object.keys(options.customMetadata).every((key) => {
|
|
2796
|
+
return key in fileEntry && fileEntry[key] === options.customMetadata[key];
|
|
2797
|
+
});
|
|
2798
|
+
if (matches) {
|
|
2799
|
+
targetFileIndex = i;
|
|
2800
|
+
this.logger.debug?.(`[FileDatabase] Found existing file with matching custom metadata: ${fileEntry.fileName}, metadata: ${JSON.stringify(options.customMetadata)}`);
|
|
2801
|
+
break;
|
|
2802
|
+
} else {
|
|
2803
|
+
this.logger.debug?.(`[FileDatabase] File ${fileEntry.fileName} does not match custom metadata: ${JSON.stringify(options.customMetadata)}`);
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
if (targetFileIndex === null) {
|
|
2807
|
+
this.logger.debug?.(`[FileDatabase] No existing file found with custom metadata: ${JSON.stringify(options.customMetadata)}, will create new file`);
|
|
2808
|
+
}
|
|
2809
|
+
} else {
|
|
2810
|
+
this.logger.debug?.(`[FileDatabase] No custom metadata provided, will create new file`);
|
|
2811
|
+
}
|
|
2812
|
+
if (targetFileIndex !== null) {
|
|
2813
|
+
const targetFile = this.metadata.files[targetFileIndex];
|
|
2814
|
+
this.currentFileNumber = targetFile.number;
|
|
2815
|
+
this.lastFileData = null;
|
|
2816
|
+
this.currentRecord = 0;
|
|
2817
|
+
this.hasReadFirstPage = false;
|
|
2818
|
+
}
|
|
2819
|
+
const forceNewFile = hasCustomMetadata && targetFileIndex === null;
|
|
2820
|
+
let { dataToWrite, dataLeftOver, fileName } = this.figureOutDataAndFileToWrite(data, targetFileIndex, forceNewFile);
|
|
2721
2821
|
const destPath = this.getDestinationPath(this.currentVersion || void 0);
|
|
2722
2822
|
await this.safeWrite(path3.join(destPath, fileName), dataToWrite);
|
|
2723
|
-
this.updateMetadata(dataToWrite, fileName);
|
|
2724
|
-
while (dataLeftOver && dataLeftOver.length > 0) {
|
|
2823
|
+
this.updateMetadata(dataToWrite, fileName, options.customMetadata);
|
|
2824
|
+
while (dataLeftOver && dataLeftOver.length > 0 && targetFileIndex === null) {
|
|
2725
2825
|
const writeContext = this.figureOutDataAndFileToWrite(dataLeftOver);
|
|
2726
2826
|
await this.safeWrite(path3.join(destPath, writeContext.fileName), writeContext.dataToWrite);
|
|
2727
|
-
this.updateMetadata(writeContext.dataToWrite, writeContext.fileName);
|
|
2827
|
+
this.updateMetadata(writeContext.dataToWrite, writeContext.fileName, options.customMetadata);
|
|
2728
2828
|
dataLeftOver = writeContext.dataLeftOver;
|
|
2729
2829
|
}
|
|
2730
2830
|
this.calculateVersionSynopsis();
|
|
@@ -2841,7 +2941,85 @@ var FileDatabase = class {
|
|
|
2841
2941
|
getMetadata() {
|
|
2842
2942
|
return { ...this.metadata };
|
|
2843
2943
|
}
|
|
2944
|
+
/**
|
|
2945
|
+
* Find data by custom metadata fields
|
|
2946
|
+
* Searches through all versions and files to find entries matching the search criteria
|
|
2947
|
+
*
|
|
2948
|
+
* @param searchCriteria - Object with field names and values to search for (e.g., { ListingKey: "123", id: "456" })
|
|
2949
|
+
* @returns Array of found entries with their file paths and metadata
|
|
2950
|
+
*/
|
|
2951
|
+
async findData(searchCriteria) {
|
|
2952
|
+
const results = [];
|
|
2953
|
+
if (!this.versioned) {
|
|
2954
|
+
await this.prepare({ read: true });
|
|
2955
|
+
const metadata = this.getMetadata();
|
|
2956
|
+
for (const fileEntry of metadata.files) {
|
|
2957
|
+
const matches = Object.keys(searchCriteria).every((key) => {
|
|
2958
|
+
return fileEntry[key] === searchCriteria[key];
|
|
2959
|
+
});
|
|
2960
|
+
if (matches) {
|
|
2961
|
+
const destPath = this.getDestinationPath();
|
|
2962
|
+
const filePath = path3.join(destPath, fileEntry.fileName);
|
|
2963
|
+
const fileData = await fs3.promises.readFile(filePath, "utf8");
|
|
2964
|
+
const data = deserializeData(fileData, metadata.dataType || "json-object");
|
|
2965
|
+
results.push({
|
|
2966
|
+
filePath,
|
|
2967
|
+
fileName: fileEntry.fileName,
|
|
2968
|
+
version: null,
|
|
2969
|
+
metadata: fileEntry,
|
|
2970
|
+
data
|
|
2971
|
+
});
|
|
2972
|
+
}
|
|
2973
|
+
}
|
|
2974
|
+
} else {
|
|
2975
|
+
const versions = await this.getVersions();
|
|
2976
|
+
for (const version of versions) {
|
|
2977
|
+
await this.prepare({ read: true, version });
|
|
2978
|
+
const metadata = this.getMetadata();
|
|
2979
|
+
for (const fileEntry of metadata.files) {
|
|
2980
|
+
const matches = Object.keys(searchCriteria).every((key) => {
|
|
2981
|
+
return fileEntry[key] === searchCriteria[key];
|
|
2982
|
+
});
|
|
2983
|
+
if (matches) {
|
|
2984
|
+
const destPath = this.getDestinationPath(version);
|
|
2985
|
+
const filePath = path3.join(destPath, fileEntry.fileName);
|
|
2986
|
+
const fileData = await fs3.promises.readFile(filePath, "utf8");
|
|
2987
|
+
const data = deserializeData(fileData, metadata.dataType || "json-object");
|
|
2988
|
+
results.push({
|
|
2989
|
+
filePath,
|
|
2990
|
+
fileName: fileEntry.fileName,
|
|
2991
|
+
version,
|
|
2992
|
+
metadata: fileEntry,
|
|
2993
|
+
data
|
|
2994
|
+
});
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
return results;
|
|
3000
|
+
}
|
|
2844
3001
|
};
|
|
3002
|
+
function listTables(basePath, namespace) {
|
|
3003
|
+
const namespacePath = path3.join(basePath, namespace);
|
|
3004
|
+
if (!fs3.existsSync(namespacePath)) {
|
|
3005
|
+
return [];
|
|
3006
|
+
}
|
|
3007
|
+
try {
|
|
3008
|
+
return fs3.readdirSync(namespacePath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
3009
|
+
} catch (error) {
|
|
3010
|
+
return [];
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
function listSources(basePath) {
|
|
3014
|
+
if (!fs3.existsSync(basePath)) {
|
|
3015
|
+
return [];
|
|
3016
|
+
}
|
|
3017
|
+
try {
|
|
3018
|
+
return fs3.readdirSync(basePath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
3019
|
+
} catch (error) {
|
|
3020
|
+
return [];
|
|
3021
|
+
}
|
|
3022
|
+
}
|
|
2845
3023
|
function fileDatabaseInit(context, options = {}) {
|
|
2846
3024
|
return new FileDatabase(context, options);
|
|
2847
3025
|
}
|
|
@@ -3633,6 +3811,8 @@ export {
|
|
|
3633
3811
|
createElement2 as h,
|
|
3634
3812
|
joiEdateType,
|
|
3635
3813
|
joiStringArrayType,
|
|
3814
|
+
listSources,
|
|
3815
|
+
listTables,
|
|
3636
3816
|
load,
|
|
3637
3817
|
organizeFooterMessages,
|
|
3638
3818
|
setupContext,
|