@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.cjs
CHANGED
|
@@ -684,6 +684,8 @@ async function showScreen(config2) {
|
|
|
684
684
|
keyMatches = true;
|
|
685
685
|
} else if (input === binding.key) {
|
|
686
686
|
keyMatches = true;
|
|
687
|
+
} else if (key?.name === binding.key) {
|
|
688
|
+
keyMatches = true;
|
|
687
689
|
}
|
|
688
690
|
if (keyMatches) {
|
|
689
691
|
if (binding.enabled === false) {
|
|
@@ -1120,6 +1122,8 @@ __export(src_exports, {
|
|
|
1120
1122
|
h: () => import_react5.createElement,
|
|
1121
1123
|
joiEdateType: () => joiEdateType,
|
|
1122
1124
|
joiStringArrayType: () => joiStringArrayType,
|
|
1125
|
+
listSources: () => listSources,
|
|
1126
|
+
listTables: () => listTables,
|
|
1123
1127
|
load: () => load,
|
|
1124
1128
|
organizeFooterMessages: () => organizeFooterMessages,
|
|
1125
1129
|
setupContext: () => setupContext,
|
|
@@ -2587,20 +2591,48 @@ var FileDatabase = class {
|
|
|
2587
2591
|
}
|
|
2588
2592
|
/**
|
|
2589
2593
|
* Figure out what data to write and which file to use (for pagination)
|
|
2594
|
+
* @param data - Data to write
|
|
2595
|
+
* @param targetFileIndex - Optional index of existing file to overwrite (when customMetadata matches)
|
|
2596
|
+
* @param forceNewFile - If true, always create a new file (when customMetadata provided but no match)
|
|
2590
2597
|
*/
|
|
2591
|
-
figureOutDataAndFileToWrite(data) {
|
|
2598
|
+
figureOutDataAndFileToWrite(data, targetFileIndex = null, forceNewFile = false) {
|
|
2592
2599
|
let dataToWrite;
|
|
2593
2600
|
let dataLeftOver;
|
|
2594
2601
|
const incomingDataType = detectDataType(data);
|
|
2595
2602
|
if (this.metadata.dataType !== incomingDataType) {
|
|
2596
2603
|
this.metadata.dataType = incomingDataType;
|
|
2597
2604
|
}
|
|
2598
|
-
if (this.metadata.files.length
|
|
2605
|
+
if (targetFileIndex !== null && targetFileIndex < this.metadata.files.length) {
|
|
2606
|
+
const targetFile = this.metadata.files[targetFileIndex];
|
|
2607
|
+
if (!Array.isArray(data)) {
|
|
2608
|
+
dataToWrite = data;
|
|
2609
|
+
dataLeftOver = null;
|
|
2610
|
+
return { dataToWrite, dataLeftOver, fileName: targetFile.fileName };
|
|
2611
|
+
} else {
|
|
2612
|
+
dataToWrite = data.slice(0, this.pageSize);
|
|
2613
|
+
dataLeftOver = data.slice(this.pageSize);
|
|
2614
|
+
this.lastFileData = dataToWrite;
|
|
2615
|
+
return { dataToWrite, dataLeftOver, fileName: targetFile.fileName };
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
let newlyCreatedFileIndex = null;
|
|
2619
|
+
if (forceNewFile) {
|
|
2620
|
+
const filesBeforeCreate = this.metadata.files.length;
|
|
2621
|
+
this.makeNewFile();
|
|
2622
|
+
newlyCreatedFileIndex = filesBeforeCreate;
|
|
2623
|
+
this.logger.debug?.(`[FileDatabase] Creating new file for unique custom metadata combination, fileNumber: ${this.currentFileNumber}`);
|
|
2624
|
+
} else if (this.metadata.files.length === 0) {
|
|
2599
2625
|
this.makeNewFile();
|
|
2600
2626
|
}
|
|
2601
2627
|
const lastFile = this.metadata.files[this.metadata.files.length - 1];
|
|
2602
2628
|
const lastFileRecordsCount = lastFile.recordsCount;
|
|
2603
|
-
if (
|
|
2629
|
+
if (forceNewFile && newlyCreatedFileIndex !== null) {
|
|
2630
|
+
const newlyCreatedFile = this.metadata.files[newlyCreatedFileIndex];
|
|
2631
|
+
if (newlyCreatedFile && newlyCreatedFile.fileName !== lastFile.fileName) {
|
|
2632
|
+
this.logger.warn?.(`[FileDatabase] Warning: Newly created file ${newlyCreatedFile.fileName} doesn't match last file ${lastFile.fileName}`);
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
if (!Array.isArray(data) && !forceNewFile) {
|
|
2604
2636
|
const lastFileExtension = import_path4.default.extname(lastFile.fileName);
|
|
2605
2637
|
const expectedExtension = `.${getFileExtension(incomingDataType)}`;
|
|
2606
2638
|
if (lastFileExtension !== expectedExtension) {
|
|
@@ -2610,24 +2642,35 @@ var FileDatabase = class {
|
|
|
2610
2642
|
lastFile.fileName = `${this.currentFileNumber.toString().padStart(6, "0")}.${getFileExtension(incomingDataType)}`;
|
|
2611
2643
|
}
|
|
2612
2644
|
}
|
|
2645
|
+
} else if (!Array.isArray(data) && forceNewFile) {
|
|
2646
|
+
const lastFileExtension = import_path4.default.extname(lastFile.fileName);
|
|
2647
|
+
const expectedExtension = `.${getFileExtension(incomingDataType)}`;
|
|
2648
|
+
if (lastFileExtension !== expectedExtension) {
|
|
2649
|
+
lastFile.fileName = `${this.currentFileNumber.toString().padStart(6, "0")}.${getFileExtension(incomingDataType)}`;
|
|
2650
|
+
}
|
|
2613
2651
|
}
|
|
2614
2652
|
if (Array.isArray(data)) {
|
|
2615
|
-
if (
|
|
2653
|
+
if (forceNewFile) {
|
|
2654
|
+
dataToWrite = data.slice(0, this.pageSize);
|
|
2655
|
+
dataLeftOver = data.slice(this.pageSize);
|
|
2656
|
+
this.lastFileData = dataToWrite;
|
|
2657
|
+
} else if (lastFileRecordsCount < this.pageSize) {
|
|
2616
2658
|
dataToWrite = [...this.lastFileData || [], ...data.slice(0, this.pageSize - lastFileRecordsCount)];
|
|
2617
2659
|
dataLeftOver = data.slice(this.pageSize - lastFileRecordsCount);
|
|
2660
|
+
this.lastFileData = dataToWrite;
|
|
2618
2661
|
} else {
|
|
2619
2662
|
this.makeNewFile();
|
|
2620
2663
|
dataToWrite = data.slice(0, this.pageSize);
|
|
2621
2664
|
dataLeftOver = data.slice(this.pageSize);
|
|
2665
|
+
this.lastFileData = dataToWrite;
|
|
2622
2666
|
}
|
|
2623
|
-
this.lastFileData = dataToWrite;
|
|
2624
2667
|
} else {
|
|
2625
2668
|
dataToWrite = data;
|
|
2626
2669
|
dataLeftOver = null;
|
|
2627
2670
|
}
|
|
2628
2671
|
const fileName = this.metadata.files[this.metadata.files.length - 1].fileName;
|
|
2629
2672
|
this.logger.debug?.(
|
|
2630
|
-
`[FileDatabase] figureOutDataAndFileToWrite: filename=${fileName}, dataToWrite.length=${Array.isArray(dataToWrite) ? dataToWrite.length : "N/A"}, lastFileRecordsCount=${lastFileRecordsCount}`
|
|
2673
|
+
`[FileDatabase] figureOutDataAndFileToWrite: filename=${fileName}, forceNewFile=${forceNewFile}, targetFileIndex=${targetFileIndex}, dataToWrite.length=${Array.isArray(dataToWrite) ? dataToWrite.length : "N/A"}, lastFileRecordsCount=${lastFileRecordsCount}`
|
|
2631
2674
|
);
|
|
2632
2675
|
return { dataToWrite, dataLeftOver, fileName };
|
|
2633
2676
|
}
|
|
@@ -2655,7 +2698,7 @@ var FileDatabase = class {
|
|
|
2655
2698
|
/**
|
|
2656
2699
|
* Update metadata after writing data
|
|
2657
2700
|
*/
|
|
2658
|
-
updateMetadata(dataToWrite, fileName) {
|
|
2701
|
+
updateMetadata(dataToWrite, fileName, customMetadata) {
|
|
2659
2702
|
let currentFile;
|
|
2660
2703
|
if (fileName) {
|
|
2661
2704
|
const foundFile = this.metadata.files.find((file) => file.fileName === fileName);
|
|
@@ -2670,6 +2713,9 @@ var FileDatabase = class {
|
|
|
2670
2713
|
}
|
|
2671
2714
|
const recordsCount = Array.isArray(dataToWrite) ? dataToWrite.length : 1;
|
|
2672
2715
|
currentFile.recordsCount = recordsCount;
|
|
2716
|
+
if (customMetadata) {
|
|
2717
|
+
Object.assign(currentFile, customMetadata);
|
|
2718
|
+
}
|
|
2673
2719
|
const fileIndex = this.metadata.files.indexOf(currentFile);
|
|
2674
2720
|
if (fileIndex !== -1) {
|
|
2675
2721
|
this.calculateFileSynopsis(dataToWrite, fileIndex);
|
|
@@ -2722,6 +2768,11 @@ var FileDatabase = class {
|
|
|
2722
2768
|
} else {
|
|
2723
2769
|
if (!this.metadata.files.length) {
|
|
2724
2770
|
this.metadata = await this.figureMetadata(this.currentVersion);
|
|
2771
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
2772
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
2773
|
+
} else {
|
|
2774
|
+
this.currentFileNumber = 0;
|
|
2775
|
+
}
|
|
2725
2776
|
}
|
|
2726
2777
|
}
|
|
2727
2778
|
} else {
|
|
@@ -2732,16 +2783,22 @@ var FileDatabase = class {
|
|
|
2732
2783
|
try {
|
|
2733
2784
|
const rawData = await import_fs4.default.promises.readFile(metadataPath, "utf8");
|
|
2734
2785
|
this.metadata = JSON.parse(rawData);
|
|
2786
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
2787
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
2788
|
+
} else {
|
|
2789
|
+
this.currentFileNumber = 0;
|
|
2790
|
+
}
|
|
2735
2791
|
} catch (e) {
|
|
2736
2792
|
this.metadata = this.getDefaultMetadata();
|
|
2793
|
+
this.currentFileNumber = 0;
|
|
2737
2794
|
}
|
|
2738
2795
|
} else {
|
|
2739
2796
|
this.metadata = this.getDefaultMetadata();
|
|
2740
|
-
this.
|
|
2797
|
+
this.currentFileNumber = 0;
|
|
2741
2798
|
}
|
|
2742
2799
|
} else {
|
|
2743
2800
|
this.metadata = this.getDefaultMetadata();
|
|
2744
|
-
this.
|
|
2801
|
+
this.currentFileNumber = 0;
|
|
2745
2802
|
}
|
|
2746
2803
|
}
|
|
2747
2804
|
} else if (read) {
|
|
@@ -2760,6 +2817,11 @@ var FileDatabase = class {
|
|
|
2760
2817
|
}
|
|
2761
2818
|
if (!this.metadata.files.length) {
|
|
2762
2819
|
this.metadata = await this.figureMetadata(this.currentVersion);
|
|
2820
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
2821
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
2822
|
+
} else {
|
|
2823
|
+
this.currentFileNumber = 0;
|
|
2824
|
+
}
|
|
2763
2825
|
}
|
|
2764
2826
|
} else {
|
|
2765
2827
|
this.currentVersion = null;
|
|
@@ -2773,6 +2835,11 @@ var FileDatabase = class {
|
|
|
2773
2835
|
try {
|
|
2774
2836
|
const rawData = await import_fs4.default.promises.readFile(metadataPath, "utf8");
|
|
2775
2837
|
this.metadata = JSON.parse(rawData);
|
|
2838
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
2839
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
2840
|
+
} else {
|
|
2841
|
+
this.currentFileNumber = 0;
|
|
2842
|
+
}
|
|
2776
2843
|
} catch (e) {
|
|
2777
2844
|
throw new FileDatabaseError(`Failed to read metadata: ${e.message}`);
|
|
2778
2845
|
}
|
|
@@ -2781,6 +2848,11 @@ var FileDatabase = class {
|
|
|
2781
2848
|
}
|
|
2782
2849
|
} else {
|
|
2783
2850
|
this.metadata = await this.figureMetadataFromVersionFiles("");
|
|
2851
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
2852
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
2853
|
+
} else {
|
|
2854
|
+
this.currentFileNumber = 0;
|
|
2855
|
+
}
|
|
2784
2856
|
}
|
|
2785
2857
|
}
|
|
2786
2858
|
}
|
|
@@ -2802,14 +2874,44 @@ var FileDatabase = class {
|
|
|
2802
2874
|
this.metadata.dataType = incomingDataType;
|
|
2803
2875
|
this.makeNewFile();
|
|
2804
2876
|
}
|
|
2805
|
-
let
|
|
2877
|
+
let targetFileIndex = null;
|
|
2878
|
+
const hasCustomMetadata = options.customMetadata && Object.keys(options.customMetadata).length > 0;
|
|
2879
|
+
if (hasCustomMetadata) {
|
|
2880
|
+
for (let i = 0; i < this.metadata.files.length; i++) {
|
|
2881
|
+
const fileEntry = this.metadata.files[i];
|
|
2882
|
+
const matches = Object.keys(options.customMetadata).every((key) => {
|
|
2883
|
+
return key in fileEntry && fileEntry[key] === options.customMetadata[key];
|
|
2884
|
+
});
|
|
2885
|
+
if (matches) {
|
|
2886
|
+
targetFileIndex = i;
|
|
2887
|
+
this.logger.debug?.(`[FileDatabase] Found existing file with matching custom metadata: ${fileEntry.fileName}, metadata: ${JSON.stringify(options.customMetadata)}`);
|
|
2888
|
+
break;
|
|
2889
|
+
} else {
|
|
2890
|
+
this.logger.debug?.(`[FileDatabase] File ${fileEntry.fileName} does not match custom metadata: ${JSON.stringify(options.customMetadata)}`);
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
if (targetFileIndex === null) {
|
|
2894
|
+
this.logger.debug?.(`[FileDatabase] No existing file found with custom metadata: ${JSON.stringify(options.customMetadata)}, will create new file`);
|
|
2895
|
+
}
|
|
2896
|
+
} else {
|
|
2897
|
+
this.logger.debug?.(`[FileDatabase] No custom metadata provided, will create new file`);
|
|
2898
|
+
}
|
|
2899
|
+
if (targetFileIndex !== null) {
|
|
2900
|
+
const targetFile = this.metadata.files[targetFileIndex];
|
|
2901
|
+
this.currentFileNumber = targetFile.number;
|
|
2902
|
+
this.lastFileData = null;
|
|
2903
|
+
this.currentRecord = 0;
|
|
2904
|
+
this.hasReadFirstPage = false;
|
|
2905
|
+
}
|
|
2906
|
+
const forceNewFile = hasCustomMetadata && targetFileIndex === null;
|
|
2907
|
+
let { dataToWrite, dataLeftOver, fileName } = this.figureOutDataAndFileToWrite(data, targetFileIndex, forceNewFile);
|
|
2806
2908
|
const destPath = this.getDestinationPath(this.currentVersion || void 0);
|
|
2807
2909
|
await this.safeWrite(import_path4.default.join(destPath, fileName), dataToWrite);
|
|
2808
|
-
this.updateMetadata(dataToWrite, fileName);
|
|
2809
|
-
while (dataLeftOver && dataLeftOver.length > 0) {
|
|
2910
|
+
this.updateMetadata(dataToWrite, fileName, options.customMetadata);
|
|
2911
|
+
while (dataLeftOver && dataLeftOver.length > 0 && targetFileIndex === null) {
|
|
2810
2912
|
const writeContext = this.figureOutDataAndFileToWrite(dataLeftOver);
|
|
2811
2913
|
await this.safeWrite(import_path4.default.join(destPath, writeContext.fileName), writeContext.dataToWrite);
|
|
2812
|
-
this.updateMetadata(writeContext.dataToWrite, writeContext.fileName);
|
|
2914
|
+
this.updateMetadata(writeContext.dataToWrite, writeContext.fileName, options.customMetadata);
|
|
2813
2915
|
dataLeftOver = writeContext.dataLeftOver;
|
|
2814
2916
|
}
|
|
2815
2917
|
this.calculateVersionSynopsis();
|
|
@@ -2926,7 +3028,85 @@ var FileDatabase = class {
|
|
|
2926
3028
|
getMetadata() {
|
|
2927
3029
|
return { ...this.metadata };
|
|
2928
3030
|
}
|
|
3031
|
+
/**
|
|
3032
|
+
* Find data by custom metadata fields
|
|
3033
|
+
* Searches through all versions and files to find entries matching the search criteria
|
|
3034
|
+
*
|
|
3035
|
+
* @param searchCriteria - Object with field names and values to search for (e.g., { ListingKey: "123", id: "456" })
|
|
3036
|
+
* @returns Array of found entries with their file paths and metadata
|
|
3037
|
+
*/
|
|
3038
|
+
async findData(searchCriteria) {
|
|
3039
|
+
const results = [];
|
|
3040
|
+
if (!this.versioned) {
|
|
3041
|
+
await this.prepare({ read: true });
|
|
3042
|
+
const metadata = this.getMetadata();
|
|
3043
|
+
for (const fileEntry of metadata.files) {
|
|
3044
|
+
const matches = Object.keys(searchCriteria).every((key) => {
|
|
3045
|
+
return fileEntry[key] === searchCriteria[key];
|
|
3046
|
+
});
|
|
3047
|
+
if (matches) {
|
|
3048
|
+
const destPath = this.getDestinationPath();
|
|
3049
|
+
const filePath = import_path4.default.join(destPath, fileEntry.fileName);
|
|
3050
|
+
const fileData = await import_fs4.default.promises.readFile(filePath, "utf8");
|
|
3051
|
+
const data = deserializeData(fileData, metadata.dataType || "json-object");
|
|
3052
|
+
results.push({
|
|
3053
|
+
filePath,
|
|
3054
|
+
fileName: fileEntry.fileName,
|
|
3055
|
+
version: null,
|
|
3056
|
+
metadata: fileEntry,
|
|
3057
|
+
data
|
|
3058
|
+
});
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
} else {
|
|
3062
|
+
const versions = await this.getVersions();
|
|
3063
|
+
for (const version of versions) {
|
|
3064
|
+
await this.prepare({ read: true, version });
|
|
3065
|
+
const metadata = this.getMetadata();
|
|
3066
|
+
for (const fileEntry of metadata.files) {
|
|
3067
|
+
const matches = Object.keys(searchCriteria).every((key) => {
|
|
3068
|
+
return fileEntry[key] === searchCriteria[key];
|
|
3069
|
+
});
|
|
3070
|
+
if (matches) {
|
|
3071
|
+
const destPath = this.getDestinationPath(version);
|
|
3072
|
+
const filePath = import_path4.default.join(destPath, fileEntry.fileName);
|
|
3073
|
+
const fileData = await import_fs4.default.promises.readFile(filePath, "utf8");
|
|
3074
|
+
const data = deserializeData(fileData, metadata.dataType || "json-object");
|
|
3075
|
+
results.push({
|
|
3076
|
+
filePath,
|
|
3077
|
+
fileName: fileEntry.fileName,
|
|
3078
|
+
version,
|
|
3079
|
+
metadata: fileEntry,
|
|
3080
|
+
data
|
|
3081
|
+
});
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
return results;
|
|
3087
|
+
}
|
|
2929
3088
|
};
|
|
3089
|
+
function listTables(basePath, namespace) {
|
|
3090
|
+
const namespacePath = import_path4.default.join(basePath, namespace);
|
|
3091
|
+
if (!import_fs4.default.existsSync(namespacePath)) {
|
|
3092
|
+
return [];
|
|
3093
|
+
}
|
|
3094
|
+
try {
|
|
3095
|
+
return import_fs4.default.readdirSync(namespacePath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
3096
|
+
} catch (error) {
|
|
3097
|
+
return [];
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
function listSources(basePath) {
|
|
3101
|
+
if (!import_fs4.default.existsSync(basePath)) {
|
|
3102
|
+
return [];
|
|
3103
|
+
}
|
|
3104
|
+
try {
|
|
3105
|
+
return import_fs4.default.readdirSync(basePath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
3106
|
+
} catch (error) {
|
|
3107
|
+
return [];
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
2930
3110
|
function fileDatabaseInit(context, options = {}) {
|
|
2931
3111
|
return new FileDatabase(context, options);
|
|
2932
3112
|
}
|
|
@@ -3719,6 +3899,8 @@ function setupContext(opts = {}) {
|
|
|
3719
3899
|
h,
|
|
3720
3900
|
joiEdateType,
|
|
3721
3901
|
joiStringArrayType,
|
|
3902
|
+
listSources,
|
|
3903
|
+
listTables,
|
|
3722
3904
|
load,
|
|
3723
3905
|
organizeFooterMessages,
|
|
3724
3906
|
setupContext,
|