@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/filedatabase.cjs
CHANGED
|
@@ -34,7 +34,9 @@ __export(filedatabase_exports, {
|
|
|
34
34
|
FileDatabaseError: () => FileDatabaseError,
|
|
35
35
|
defaultFileSynopsisFunction: () => defaultFileSynopsisFunction,
|
|
36
36
|
defaultVersionSynopsisFunction: () => defaultVersionSynopsisFunction,
|
|
37
|
-
fileDatabaseInit: () => fileDatabaseInit
|
|
37
|
+
fileDatabaseInit: () => fileDatabaseInit,
|
|
38
|
+
listSources: () => listSources,
|
|
39
|
+
listTables: () => listTables
|
|
38
40
|
});
|
|
39
41
|
module.exports = __toCommonJS(filedatabase_exports);
|
|
40
42
|
|
|
@@ -650,20 +652,48 @@ var FileDatabase = class {
|
|
|
650
652
|
}
|
|
651
653
|
/**
|
|
652
654
|
* Figure out what data to write and which file to use (for pagination)
|
|
655
|
+
* @param data - Data to write
|
|
656
|
+
* @param targetFileIndex - Optional index of existing file to overwrite (when customMetadata matches)
|
|
657
|
+
* @param forceNewFile - If true, always create a new file (when customMetadata provided but no match)
|
|
653
658
|
*/
|
|
654
|
-
figureOutDataAndFileToWrite(data) {
|
|
659
|
+
figureOutDataAndFileToWrite(data, targetFileIndex = null, forceNewFile = false) {
|
|
655
660
|
let dataToWrite;
|
|
656
661
|
let dataLeftOver;
|
|
657
662
|
const incomingDataType = detectDataType(data);
|
|
658
663
|
if (this.metadata.dataType !== incomingDataType) {
|
|
659
664
|
this.metadata.dataType = incomingDataType;
|
|
660
665
|
}
|
|
661
|
-
if (this.metadata.files.length
|
|
666
|
+
if (targetFileIndex !== null && targetFileIndex < this.metadata.files.length) {
|
|
667
|
+
const targetFile = this.metadata.files[targetFileIndex];
|
|
668
|
+
if (!Array.isArray(data)) {
|
|
669
|
+
dataToWrite = data;
|
|
670
|
+
dataLeftOver = null;
|
|
671
|
+
return { dataToWrite, dataLeftOver, fileName: targetFile.fileName };
|
|
672
|
+
} else {
|
|
673
|
+
dataToWrite = data.slice(0, this.pageSize);
|
|
674
|
+
dataLeftOver = data.slice(this.pageSize);
|
|
675
|
+
this.lastFileData = dataToWrite;
|
|
676
|
+
return { dataToWrite, dataLeftOver, fileName: targetFile.fileName };
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
let newlyCreatedFileIndex = null;
|
|
680
|
+
if (forceNewFile) {
|
|
681
|
+
const filesBeforeCreate = this.metadata.files.length;
|
|
682
|
+
this.makeNewFile();
|
|
683
|
+
newlyCreatedFileIndex = filesBeforeCreate;
|
|
684
|
+
this.logger.debug?.(`[FileDatabase] Creating new file for unique custom metadata combination, fileNumber: ${this.currentFileNumber}`);
|
|
685
|
+
} else if (this.metadata.files.length === 0) {
|
|
662
686
|
this.makeNewFile();
|
|
663
687
|
}
|
|
664
688
|
const lastFile = this.metadata.files[this.metadata.files.length - 1];
|
|
665
689
|
const lastFileRecordsCount = lastFile.recordsCount;
|
|
666
|
-
if (
|
|
690
|
+
if (forceNewFile && newlyCreatedFileIndex !== null) {
|
|
691
|
+
const newlyCreatedFile = this.metadata.files[newlyCreatedFileIndex];
|
|
692
|
+
if (newlyCreatedFile && newlyCreatedFile.fileName !== lastFile.fileName) {
|
|
693
|
+
this.logger.warn?.(`[FileDatabase] Warning: Newly created file ${newlyCreatedFile.fileName} doesn't match last file ${lastFile.fileName}`);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
if (!Array.isArray(data) && !forceNewFile) {
|
|
667
697
|
const lastFileExtension = import_path3.default.extname(lastFile.fileName);
|
|
668
698
|
const expectedExtension = `.${getFileExtension(incomingDataType)}`;
|
|
669
699
|
if (lastFileExtension !== expectedExtension) {
|
|
@@ -673,24 +703,35 @@ var FileDatabase = class {
|
|
|
673
703
|
lastFile.fileName = `${this.currentFileNumber.toString().padStart(6, "0")}.${getFileExtension(incomingDataType)}`;
|
|
674
704
|
}
|
|
675
705
|
}
|
|
706
|
+
} else if (!Array.isArray(data) && forceNewFile) {
|
|
707
|
+
const lastFileExtension = import_path3.default.extname(lastFile.fileName);
|
|
708
|
+
const expectedExtension = `.${getFileExtension(incomingDataType)}`;
|
|
709
|
+
if (lastFileExtension !== expectedExtension) {
|
|
710
|
+
lastFile.fileName = `${this.currentFileNumber.toString().padStart(6, "0")}.${getFileExtension(incomingDataType)}`;
|
|
711
|
+
}
|
|
676
712
|
}
|
|
677
713
|
if (Array.isArray(data)) {
|
|
678
|
-
if (
|
|
714
|
+
if (forceNewFile) {
|
|
715
|
+
dataToWrite = data.slice(0, this.pageSize);
|
|
716
|
+
dataLeftOver = data.slice(this.pageSize);
|
|
717
|
+
this.lastFileData = dataToWrite;
|
|
718
|
+
} else if (lastFileRecordsCount < this.pageSize) {
|
|
679
719
|
dataToWrite = [...this.lastFileData || [], ...data.slice(0, this.pageSize - lastFileRecordsCount)];
|
|
680
720
|
dataLeftOver = data.slice(this.pageSize - lastFileRecordsCount);
|
|
721
|
+
this.lastFileData = dataToWrite;
|
|
681
722
|
} else {
|
|
682
723
|
this.makeNewFile();
|
|
683
724
|
dataToWrite = data.slice(0, this.pageSize);
|
|
684
725
|
dataLeftOver = data.slice(this.pageSize);
|
|
726
|
+
this.lastFileData = dataToWrite;
|
|
685
727
|
}
|
|
686
|
-
this.lastFileData = dataToWrite;
|
|
687
728
|
} else {
|
|
688
729
|
dataToWrite = data;
|
|
689
730
|
dataLeftOver = null;
|
|
690
731
|
}
|
|
691
732
|
const fileName = this.metadata.files[this.metadata.files.length - 1].fileName;
|
|
692
733
|
this.logger.debug?.(
|
|
693
|
-
`[FileDatabase] figureOutDataAndFileToWrite: filename=${fileName}, dataToWrite.length=${Array.isArray(dataToWrite) ? dataToWrite.length : "N/A"}, lastFileRecordsCount=${lastFileRecordsCount}`
|
|
734
|
+
`[FileDatabase] figureOutDataAndFileToWrite: filename=${fileName}, forceNewFile=${forceNewFile}, targetFileIndex=${targetFileIndex}, dataToWrite.length=${Array.isArray(dataToWrite) ? dataToWrite.length : "N/A"}, lastFileRecordsCount=${lastFileRecordsCount}`
|
|
694
735
|
);
|
|
695
736
|
return { dataToWrite, dataLeftOver, fileName };
|
|
696
737
|
}
|
|
@@ -718,7 +759,7 @@ var FileDatabase = class {
|
|
|
718
759
|
/**
|
|
719
760
|
* Update metadata after writing data
|
|
720
761
|
*/
|
|
721
|
-
updateMetadata(dataToWrite, fileName) {
|
|
762
|
+
updateMetadata(dataToWrite, fileName, customMetadata) {
|
|
722
763
|
let currentFile;
|
|
723
764
|
if (fileName) {
|
|
724
765
|
const foundFile = this.metadata.files.find((file) => file.fileName === fileName);
|
|
@@ -733,6 +774,9 @@ var FileDatabase = class {
|
|
|
733
774
|
}
|
|
734
775
|
const recordsCount = Array.isArray(dataToWrite) ? dataToWrite.length : 1;
|
|
735
776
|
currentFile.recordsCount = recordsCount;
|
|
777
|
+
if (customMetadata) {
|
|
778
|
+
Object.assign(currentFile, customMetadata);
|
|
779
|
+
}
|
|
736
780
|
const fileIndex = this.metadata.files.indexOf(currentFile);
|
|
737
781
|
if (fileIndex !== -1) {
|
|
738
782
|
this.calculateFileSynopsis(dataToWrite, fileIndex);
|
|
@@ -785,6 +829,11 @@ var FileDatabase = class {
|
|
|
785
829
|
} else {
|
|
786
830
|
if (!this.metadata.files.length) {
|
|
787
831
|
this.metadata = await this.figureMetadata(this.currentVersion);
|
|
832
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
833
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
834
|
+
} else {
|
|
835
|
+
this.currentFileNumber = 0;
|
|
836
|
+
}
|
|
788
837
|
}
|
|
789
838
|
}
|
|
790
839
|
} else {
|
|
@@ -795,16 +844,22 @@ var FileDatabase = class {
|
|
|
795
844
|
try {
|
|
796
845
|
const rawData = await import_fs3.default.promises.readFile(metadataPath, "utf8");
|
|
797
846
|
this.metadata = JSON.parse(rawData);
|
|
847
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
848
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
849
|
+
} else {
|
|
850
|
+
this.currentFileNumber = 0;
|
|
851
|
+
}
|
|
798
852
|
} catch (e) {
|
|
799
853
|
this.metadata = this.getDefaultMetadata();
|
|
854
|
+
this.currentFileNumber = 0;
|
|
800
855
|
}
|
|
801
856
|
} else {
|
|
802
857
|
this.metadata = this.getDefaultMetadata();
|
|
803
|
-
this.
|
|
858
|
+
this.currentFileNumber = 0;
|
|
804
859
|
}
|
|
805
860
|
} else {
|
|
806
861
|
this.metadata = this.getDefaultMetadata();
|
|
807
|
-
this.
|
|
862
|
+
this.currentFileNumber = 0;
|
|
808
863
|
}
|
|
809
864
|
}
|
|
810
865
|
} else if (read) {
|
|
@@ -823,6 +878,11 @@ var FileDatabase = class {
|
|
|
823
878
|
}
|
|
824
879
|
if (!this.metadata.files.length) {
|
|
825
880
|
this.metadata = await this.figureMetadata(this.currentVersion);
|
|
881
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
882
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
883
|
+
} else {
|
|
884
|
+
this.currentFileNumber = 0;
|
|
885
|
+
}
|
|
826
886
|
}
|
|
827
887
|
} else {
|
|
828
888
|
this.currentVersion = null;
|
|
@@ -836,6 +896,11 @@ var FileDatabase = class {
|
|
|
836
896
|
try {
|
|
837
897
|
const rawData = await import_fs3.default.promises.readFile(metadataPath, "utf8");
|
|
838
898
|
this.metadata = JSON.parse(rawData);
|
|
899
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
900
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
901
|
+
} else {
|
|
902
|
+
this.currentFileNumber = 0;
|
|
903
|
+
}
|
|
839
904
|
} catch (e) {
|
|
840
905
|
throw new FileDatabaseError(`Failed to read metadata: ${e.message}`);
|
|
841
906
|
}
|
|
@@ -844,6 +909,11 @@ var FileDatabase = class {
|
|
|
844
909
|
}
|
|
845
910
|
} else {
|
|
846
911
|
this.metadata = await this.figureMetadataFromVersionFiles("");
|
|
912
|
+
if (this.metadata.files && this.metadata.files.length > 0) {
|
|
913
|
+
this.currentFileNumber = Math.max(...this.metadata.files.map((f) => f.number || 0));
|
|
914
|
+
} else {
|
|
915
|
+
this.currentFileNumber = 0;
|
|
916
|
+
}
|
|
847
917
|
}
|
|
848
918
|
}
|
|
849
919
|
}
|
|
@@ -865,14 +935,44 @@ var FileDatabase = class {
|
|
|
865
935
|
this.metadata.dataType = incomingDataType;
|
|
866
936
|
this.makeNewFile();
|
|
867
937
|
}
|
|
868
|
-
let
|
|
938
|
+
let targetFileIndex = null;
|
|
939
|
+
const hasCustomMetadata = options.customMetadata && Object.keys(options.customMetadata).length > 0;
|
|
940
|
+
if (hasCustomMetadata) {
|
|
941
|
+
for (let i = 0; i < this.metadata.files.length; i++) {
|
|
942
|
+
const fileEntry = this.metadata.files[i];
|
|
943
|
+
const matches = Object.keys(options.customMetadata).every((key) => {
|
|
944
|
+
return key in fileEntry && fileEntry[key] === options.customMetadata[key];
|
|
945
|
+
});
|
|
946
|
+
if (matches) {
|
|
947
|
+
targetFileIndex = i;
|
|
948
|
+
this.logger.debug?.(`[FileDatabase] Found existing file with matching custom metadata: ${fileEntry.fileName}, metadata: ${JSON.stringify(options.customMetadata)}`);
|
|
949
|
+
break;
|
|
950
|
+
} else {
|
|
951
|
+
this.logger.debug?.(`[FileDatabase] File ${fileEntry.fileName} does not match custom metadata: ${JSON.stringify(options.customMetadata)}`);
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
if (targetFileIndex === null) {
|
|
955
|
+
this.logger.debug?.(`[FileDatabase] No existing file found with custom metadata: ${JSON.stringify(options.customMetadata)}, will create new file`);
|
|
956
|
+
}
|
|
957
|
+
} else {
|
|
958
|
+
this.logger.debug?.(`[FileDatabase] No custom metadata provided, will create new file`);
|
|
959
|
+
}
|
|
960
|
+
if (targetFileIndex !== null) {
|
|
961
|
+
const targetFile = this.metadata.files[targetFileIndex];
|
|
962
|
+
this.currentFileNumber = targetFile.number;
|
|
963
|
+
this.lastFileData = null;
|
|
964
|
+
this.currentRecord = 0;
|
|
965
|
+
this.hasReadFirstPage = false;
|
|
966
|
+
}
|
|
967
|
+
const forceNewFile = hasCustomMetadata && targetFileIndex === null;
|
|
968
|
+
let { dataToWrite, dataLeftOver, fileName } = this.figureOutDataAndFileToWrite(data, targetFileIndex, forceNewFile);
|
|
869
969
|
const destPath = this.getDestinationPath(this.currentVersion || void 0);
|
|
870
970
|
await this.safeWrite(import_path3.default.join(destPath, fileName), dataToWrite);
|
|
871
|
-
this.updateMetadata(dataToWrite, fileName);
|
|
872
|
-
while (dataLeftOver && dataLeftOver.length > 0) {
|
|
971
|
+
this.updateMetadata(dataToWrite, fileName, options.customMetadata);
|
|
972
|
+
while (dataLeftOver && dataLeftOver.length > 0 && targetFileIndex === null) {
|
|
873
973
|
const writeContext = this.figureOutDataAndFileToWrite(dataLeftOver);
|
|
874
974
|
await this.safeWrite(import_path3.default.join(destPath, writeContext.fileName), writeContext.dataToWrite);
|
|
875
|
-
this.updateMetadata(writeContext.dataToWrite, writeContext.fileName);
|
|
975
|
+
this.updateMetadata(writeContext.dataToWrite, writeContext.fileName, options.customMetadata);
|
|
876
976
|
dataLeftOver = writeContext.dataLeftOver;
|
|
877
977
|
}
|
|
878
978
|
this.calculateVersionSynopsis();
|
|
@@ -989,7 +1089,85 @@ var FileDatabase = class {
|
|
|
989
1089
|
getMetadata() {
|
|
990
1090
|
return { ...this.metadata };
|
|
991
1091
|
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Find data by custom metadata fields
|
|
1094
|
+
* Searches through all versions and files to find entries matching the search criteria
|
|
1095
|
+
*
|
|
1096
|
+
* @param searchCriteria - Object with field names and values to search for (e.g., { ListingKey: "123", id: "456" })
|
|
1097
|
+
* @returns Array of found entries with their file paths and metadata
|
|
1098
|
+
*/
|
|
1099
|
+
async findData(searchCriteria) {
|
|
1100
|
+
const results = [];
|
|
1101
|
+
if (!this.versioned) {
|
|
1102
|
+
await this.prepare({ read: true });
|
|
1103
|
+
const metadata = this.getMetadata();
|
|
1104
|
+
for (const fileEntry of metadata.files) {
|
|
1105
|
+
const matches = Object.keys(searchCriteria).every((key) => {
|
|
1106
|
+
return fileEntry[key] === searchCriteria[key];
|
|
1107
|
+
});
|
|
1108
|
+
if (matches) {
|
|
1109
|
+
const destPath = this.getDestinationPath();
|
|
1110
|
+
const filePath = import_path3.default.join(destPath, fileEntry.fileName);
|
|
1111
|
+
const fileData = await import_fs3.default.promises.readFile(filePath, "utf8");
|
|
1112
|
+
const data = deserializeData(fileData, metadata.dataType || "json-object");
|
|
1113
|
+
results.push({
|
|
1114
|
+
filePath,
|
|
1115
|
+
fileName: fileEntry.fileName,
|
|
1116
|
+
version: null,
|
|
1117
|
+
metadata: fileEntry,
|
|
1118
|
+
data
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
} else {
|
|
1123
|
+
const versions = await this.getVersions();
|
|
1124
|
+
for (const version of versions) {
|
|
1125
|
+
await this.prepare({ read: true, version });
|
|
1126
|
+
const metadata = this.getMetadata();
|
|
1127
|
+
for (const fileEntry of metadata.files) {
|
|
1128
|
+
const matches = Object.keys(searchCriteria).every((key) => {
|
|
1129
|
+
return fileEntry[key] === searchCriteria[key];
|
|
1130
|
+
});
|
|
1131
|
+
if (matches) {
|
|
1132
|
+
const destPath = this.getDestinationPath(version);
|
|
1133
|
+
const filePath = import_path3.default.join(destPath, fileEntry.fileName);
|
|
1134
|
+
const fileData = await import_fs3.default.promises.readFile(filePath, "utf8");
|
|
1135
|
+
const data = deserializeData(fileData, metadata.dataType || "json-object");
|
|
1136
|
+
results.push({
|
|
1137
|
+
filePath,
|
|
1138
|
+
fileName: fileEntry.fileName,
|
|
1139
|
+
version,
|
|
1140
|
+
metadata: fileEntry,
|
|
1141
|
+
data
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
return results;
|
|
1148
|
+
}
|
|
992
1149
|
};
|
|
1150
|
+
function listTables(basePath, namespace) {
|
|
1151
|
+
const namespacePath = import_path3.default.join(basePath, namespace);
|
|
1152
|
+
if (!import_fs3.default.existsSync(namespacePath)) {
|
|
1153
|
+
return [];
|
|
1154
|
+
}
|
|
1155
|
+
try {
|
|
1156
|
+
return import_fs3.default.readdirSync(namespacePath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
1157
|
+
} catch (error) {
|
|
1158
|
+
return [];
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
function listSources(basePath) {
|
|
1162
|
+
if (!import_fs3.default.existsSync(basePath)) {
|
|
1163
|
+
return [];
|
|
1164
|
+
}
|
|
1165
|
+
try {
|
|
1166
|
+
return import_fs3.default.readdirSync(basePath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
1167
|
+
} catch (error) {
|
|
1168
|
+
return [];
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
993
1171
|
function fileDatabaseInit(context, options = {}) {
|
|
994
1172
|
return new FileDatabase(context, options);
|
|
995
1173
|
}
|
|
@@ -999,6 +1177,8 @@ function fileDatabaseInit(context, options = {}) {
|
|
|
999
1177
|
FileDatabaseError,
|
|
1000
1178
|
defaultFileSynopsisFunction,
|
|
1001
1179
|
defaultVersionSynopsisFunction,
|
|
1002
|
-
fileDatabaseInit
|
|
1180
|
+
fileDatabaseInit,
|
|
1181
|
+
listSources,
|
|
1182
|
+
listTables
|
|
1003
1183
|
});
|
|
1004
1184
|
//# sourceMappingURL=filedatabase.cjs.map
|