@irfanshadikrishad/anilist 1.2.10 → 1.2.11

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.
@@ -8,10 +8,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { XMLParser } from "fast-xml-parser";
11
- import { readFile, writeFile } from "fs/promises";
11
+ import { readFile } from "fs/promises";
12
12
  import inquirer from "inquirer";
13
13
  import { jsonrepair } from "jsonrepair";
14
- import open from "open";
15
14
  import { join } from "path";
16
15
  import { Auth } from "./auth.js";
17
16
  import { fetcher } from "./fetcher.js";
@@ -19,7 +18,7 @@ import { addAnimeToListMutation, addMangaToListMutation, saveAnimeWithProgressMu
19
18
  import { animeDetailsQuery, animeSearchQuery, currentUserAnimeList, currentUserMangaList, malIdToAnilistAnimeId, malIdToAnilistMangaId, mangaSearchQuery, popularQuery, trendingQuery, upcomingAnimesQuery, userActivityQuery, userFollowersQuery, userFollowingQuery, userQuery, } from "./queries.js";
20
19
  import { AniListMediaStatus, } from "./types.js";
21
20
  import { Validate } from "./validation.js";
22
- import { anidbToanilistMapper, createAnimeListXML, createMangaListXML, formatDateObject, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, timestampToTimeAgo, } from "./workers.js";
21
+ import { anidbToanilistMapper, formatDateObject, getDownloadFolderPath, getNextSeasonAndYear, getTitle, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, saveJSONasXML, selectFile, timestampToTimeAgo, } from "./workers.js";
23
22
  class AniList {
24
23
  static importAnime() {
25
24
  return __awaiter(this, void 0, void 0, function* () {
@@ -152,14 +151,12 @@ class AniList {
152
151
  if (animeList) {
153
152
  const lists = (_c = (_b = (_a = animeList === null || animeList === void 0 ? void 0 : animeList.data) === null || _a === void 0 ? void 0 : _a.MediaListCollection) === null || _b === void 0 ? void 0 : _b.lists) !== null && _c !== void 0 ? _c : [];
154
153
  const mediaWithProgress = lists.flatMap((list) => list.entries.map((entry) => {
155
- var _a, _b, _c, _d, _e;
154
+ var _a, _b, _c, _d;
156
155
  return ({
157
156
  id: (_a = entry === null || entry === void 0 ? void 0 : entry.media) === null || _a === void 0 ? void 0 : _a.id,
158
- title: exportType === 1
159
- ? getTitle((_b = entry === null || entry === void 0 ? void 0 : entry.media) === null || _b === void 0 ? void 0 : _b.title)
160
- : (_c = entry === null || entry === void 0 ? void 0 : entry.media) === null || _c === void 0 ? void 0 : _c.title,
161
- episodes: (_d = entry === null || entry === void 0 ? void 0 : entry.media) === null || _d === void 0 ? void 0 : _d.episodes,
162
- siteUrl: (_e = entry === null || entry === void 0 ? void 0 : entry.media) === null || _e === void 0 ? void 0 : _e.siteUrl,
157
+ title: (_b = entry === null || entry === void 0 ? void 0 : entry.media) === null || _b === void 0 ? void 0 : _b.title,
158
+ episodes: (_c = entry === null || entry === void 0 ? void 0 : entry.media) === null || _c === void 0 ? void 0 : _c.episodes,
159
+ siteUrl: (_d = entry === null || entry === void 0 ? void 0 : entry.media) === null || _d === void 0 ? void 0 : _d.siteUrl,
163
160
  progress: entry.progress,
164
161
  status: entry === null || entry === void 0 ? void 0 : entry.status,
165
162
  hiddenFromStatusLists: entry.hiddenFromStatusLists,
@@ -215,12 +212,10 @@ class AniList {
215
212
  },
216
213
  ]);
217
214
  const mediaWithProgress = lists.flatMap((list) => list.entries.map((entry) => {
218
- var _a, _b, _c;
215
+ var _a, _b;
219
216
  return ({
220
217
  id: (_a = entry === null || entry === void 0 ? void 0 : entry.media) === null || _a === void 0 ? void 0 : _a.id,
221
- title: exportType === 1
222
- ? getTitle((_b = entry === null || entry === void 0 ? void 0 : entry.media) === null || _b === void 0 ? void 0 : _b.title)
223
- : (_c = entry === null || entry === void 0 ? void 0 : entry.media) === null || _c === void 0 ? void 0 : _c.title,
218
+ title: (_b = entry === null || entry === void 0 ? void 0 : entry.media) === null || _b === void 0 ? void 0 : _b.title,
224
219
  private: entry.private,
225
220
  chapters: entry.media.chapters,
226
221
  progress: entry.progress,
@@ -979,7 +974,7 @@ class MyAnimeList {
979
974
  if (((_b = (_a = animeList === null || animeList === void 0 ? void 0 : animeList.data) === null || _a === void 0 ? void 0 : _a.MediaListCollection) === null || _b === void 0 ? void 0 : _b.lists.length) > 0) {
980
975
  const lists = (_d = (_c = animeList === null || animeList === void 0 ? void 0 : animeList.data) === null || _c === void 0 ? void 0 : _c.MediaListCollection) === null || _d === void 0 ? void 0 : _d.lists;
981
976
  const mediaWithProgress = lists.flatMap((list) => list.entries.map((entry) => {
982
- var _a, _b, _c, _d, _e;
977
+ var _a, _b, _c, _d, _e, _f;
983
978
  return ({
984
979
  id: (_a = entry === null || entry === void 0 ? void 0 : entry.media) === null || _a === void 0 ? void 0 : _a.id,
985
980
  malId: (_b = entry === null || entry === void 0 ? void 0 : entry.media) === null || _b === void 0 ? void 0 : _b.idMal,
@@ -989,13 +984,10 @@ class MyAnimeList {
989
984
  progress: entry.progress,
990
985
  status: entry === null || entry === void 0 ? void 0 : entry.status,
991
986
  hiddenFromStatusLists: false,
987
+ format: (_f = entry === null || entry === void 0 ? void 0 : entry.media) === null || _f === void 0 ? void 0 : _f.format,
992
988
  });
993
989
  }));
994
- const xmlContent = createAnimeListXML(mediaWithProgress);
995
- const path = join(getDownloadFolderPath(), `${yield Auth.MyUserName()}@irfanshadikrishad-anilist-myanimelist(anime)-${getFormattedDate()}.xml`);
996
- yield writeFile(path, yield xmlContent, "utf8");
997
- console.log(`Generated XML for MyAnimeList.`);
998
- open(getDownloadFolderPath());
990
+ yield saveJSONasXML(mediaWithProgress, 0);
999
991
  }
1000
992
  else {
1001
993
  console.log(`\nHey, ${yield Auth.MyUserName()}. Your anime list seems to be empty.`);
@@ -1030,11 +1022,7 @@ class MyAnimeList {
1030
1022
  status: entry.status,
1031
1023
  hiddenFromStatusLists: entry.hiddenFromStatusLists,
1032
1024
  })));
1033
- const XMLContent = createMangaListXML(mediaWithProgress);
1034
- const path = join(getDownloadFolderPath(), `${yield Auth.MyUserName()}@irfanshadikrishad-anilist-myanimelist(manga)-${getFormattedDate()}.xml`);
1035
- yield writeFile(path, yield XMLContent, "utf8");
1036
- console.log(`Generated XML for MyAnimeList.`);
1037
- open(getDownloadFolderPath());
1025
+ yield saveJSONasXML(mediaWithProgress, 1);
1038
1026
  }
1039
1027
  else {
1040
1028
  console.log(`\nHey, ${yield Auth.MyUserName()}. Your anime list seems to be empty.`);
@@ -2,8 +2,8 @@ declare const currentUserQuery = "{\n Viewer {\n id name about bans siteUrl
2
2
  declare const trendingQuery = "query ($page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n media(sort: TRENDING_DESC, type: ANIME) { id title { romaji english } }\n }\n}";
3
3
  declare const popularQuery = "query ($page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n media(sort: POPULARITY_DESC, type: ANIME) { id title { romaji english } }\n }\n}";
4
4
  declare const userQuery = "query ($username: String) {\n User(name: $username) {\n id name siteUrl donatorTier donatorBadge createdAt updatedAt previousNames { name createdAt updatedAt }\n isBlocked isFollower isFollowing options { profileColor timezone activityMergeTime }\n statistics { anime { count episodesWatched minutesWatched } manga { count chaptersRead volumesRead } }\n }\n}";
5
- declare const currentUserAnimeList = "query ($id: Int) {\n MediaListCollection(userId: $id, type: ANIME) {\n lists { name entries { id progress hiddenFromStatusLists status media { id idMal title { romaji english } status episodes siteUrl } } }\n }\n}\n";
6
- declare const currentUserMangaList = "query ($id: Int) {\n MediaListCollection(userId: $id, type: MANGA) {\n lists { name entries { id progress hiddenFromStatusLists private status media { id idMal title { romaji english } status chapters } } }\n }\n}\n";
5
+ declare const currentUserAnimeList = "query ($id: Int) {\n MediaListCollection(userId: $id, type: ANIME) {\n lists { name entries { id progress hiddenFromStatusLists status media { id idMal title { romaji english native userPreferred } status episodes siteUrl format } } }\n }\n}\n";
6
+ declare const currentUserMangaList = "query ($id: Int) {\n MediaListCollection(userId: $id, type: MANGA) {\n lists { name entries { id progress hiddenFromStatusLists private status media { id idMal title { romaji english native userPreferred } status chapters } } }\n }\n}\n";
7
7
  declare const deleteMediaEntryMutation = "mutation($id: Int!) {\n DeleteMediaListEntry(id: $id) { deleted }\n}";
8
8
  declare const deleteMangaEntryMutation = "mutation($id: Int) {\n DeleteMediaListEntry(id: $id) { deleted }\n}";
9
9
  declare const upcomingAnimesQuery = "query GetNextSeasonAnime($nextSeason: MediaSeason, $nextYear: Int, $perPage: Int) {\n Page(perPage: $perPage) {\n media(season: $nextSeason, seasonYear: $nextYear, type: ANIME, sort: POPULARITY_DESC) {\n id title { romaji english native userPreferred } season seasonYear startDate { year month day }\n episodes description genres\n }\n }\n}";
@@ -26,13 +26,13 @@ const userQuery = `query ($username: String) {
26
26
  }`;
27
27
  const currentUserAnimeList = `query ($id: Int) {
28
28
  MediaListCollection(userId: $id, type: ANIME) {
29
- lists { name entries { id progress hiddenFromStatusLists status media { id idMal title { romaji english } status episodes siteUrl } } }
29
+ lists { name entries { id progress hiddenFromStatusLists status media { id idMal title { romaji english native userPreferred } status episodes siteUrl format } } }
30
30
  }
31
31
  }
32
32
  `;
33
33
  const currentUserMangaList = `query ($id: Int) {
34
34
  MediaListCollection(userId: $id, type: MANGA) {
35
- lists { name entries { id progress hiddenFromStatusLists private status media { id idMal title { romaji english } status chapters } } }
35
+ lists { name entries { id progress hiddenFromStatusLists private status media { id idMal title { romaji english native userPreferred } status chapters } } }
36
36
  }
37
37
  }
38
38
  `;
@@ -45,10 +45,7 @@ interface MalIdToAnilistIdResponse {
45
45
  data?: {
46
46
  Media: {
47
47
  id: number;
48
- title: {
49
- english?: string;
50
- romaji?: string;
51
- };
48
+ title: MediaTitle;
52
49
  };
53
50
  };
54
51
  errors?: {
@@ -92,15 +89,13 @@ interface AnimeList {
92
89
  }[];
93
90
  }
94
91
  interface MediaWithProgress {
95
- malId: number;
92
+ malId?: number;
96
93
  progress: number;
97
94
  status: string;
98
95
  episodes?: number;
99
96
  chapters?: number;
100
- title: {
101
- english?: string;
102
- romaji?: string;
103
- };
97
+ format?: string;
98
+ title: MediaTitle;
104
99
  }
105
100
  interface MediaTitle {
106
101
  english?: string;
@@ -150,10 +145,7 @@ interface List {
150
145
  }
151
146
  interface MediaList {
152
147
  id(id: number | string): string;
153
- title: {
154
- english?: string;
155
- romaji?: string;
156
- };
148
+ title: MediaTitle;
157
149
  name: string;
158
150
  entries: MediaListEntry[];
159
151
  }
@@ -240,6 +232,7 @@ interface MediaListEntry {
240
232
  episodes?: number;
241
233
  siteUrl?: string;
242
234
  chapters?: number;
235
+ format?: string;
243
236
  };
244
237
  progress?: number;
245
238
  status?: string;
@@ -20,21 +20,29 @@ declare function getFormattedDate(): string;
20
20
  /**
21
21
  * Export JSON as JSON
22
22
  * @param js0n
23
- * @param dataType (eg: anime/manga)
23
+ * @param dataType (eg: anime|manga)
24
24
  */
25
25
  declare function saveJSONasJSON(js0n: object, dataType: string): Promise<void>;
26
26
  /**
27
27
  * Export JSON as CSV
28
28
  * @param js0n
29
- * @param dataType (eg: anime/manga)
29
+ * @param dataType (eg: anime|manga)
30
30
  */
31
- declare function saveJSONasCSV(js0n: object, dataType: string): Promise<void>;
31
+ declare function saveJSONasCSV(js0n: MediaWithProgress[], dataType: string): Promise<void>;
32
+ declare function saveJSONasXML(js0n: MediaWithProgress[], data_type: 0 | 1): Promise<void>;
32
33
  declare function selectFile(fileType: string): Promise<string>;
33
- declare function createAnimeXML(malId: number, progress: number, status: MALAnimeStatus, episodes: number, title: string): string;
34
+ declare function createAnimeXML(malId: number, progress: number, status: MALAnimeStatus, episodes: number, title: string, format: string): string;
34
35
  declare function createMangaXML(malId: number, progress: number, status: MALMangaStatus, chapters: number, title: string): string;
35
36
  declare function createAnimeListXML(mediaWithProgress: MediaWithProgress[]): Promise<string>;
36
37
  declare function createMangaListXML(mediaWithProgress: MediaWithProgress[]): Promise<string>;
37
38
  declare function getCurrentPackageVersion(): string | null;
38
39
  declare function timestampToTimeAgo(timestamp: number): string;
39
40
  declare const anidbToanilistMapper: (romanjiName: string, year: number, englishName?: string) => Promise<number | null>;
40
- export { anidbToanilistMapper, aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getCurrentPackageVersion, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, timestampToTimeAgo, };
41
+ /**
42
+ * Extract the save file path
43
+ * @param data_type - anime|manga
44
+ * @param file_format - save format (eg: .json|.csv)
45
+ * @returns string of file path
46
+ */
47
+ declare function saveToPath(data_type: string, file_format: string): Promise<string>;
48
+ export { anidbToanilistMapper, aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getCurrentPackageVersion, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, saveJSONasXML, saveToPath, selectFile, timestampToTimeAgo, };
@@ -7,13 +7,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
+ var __rest = (this && this.__rest) || function (s, e) {
11
+ var t = {};
12
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
13
+ t[p] = s[p];
14
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
15
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
16
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
17
+ t[p[i]] = s[p[i]];
18
+ }
19
+ return t;
20
+ };
10
21
  import fs from "fs";
11
22
  import { readdir, writeFile } from "fs/promises";
12
23
  import inquirer from "inquirer";
13
- import { parse } from "json2csv";
14
24
  import { createRequire } from "module";
15
25
  import open from "open";
16
26
  import { homedir } from "os";
27
+ import Papa from "papaparse";
17
28
  import { join } from "path";
18
29
  import process from "process";
19
30
  import { Auth } from "./auth.js";
@@ -97,13 +108,13 @@ function getFormattedDate() {
97
108
  /**
98
109
  * Export JSON as JSON
99
110
  * @param js0n
100
- * @param dataType (eg: anime/manga)
111
+ * @param dataType (eg: anime|manga)
101
112
  */
102
113
  function saveJSONasJSON(js0n, dataType) {
103
114
  return __awaiter(this, void 0, void 0, function* () {
104
115
  try {
105
116
  const jsonData = JSON.stringify(js0n, null, 2);
106
- const path = join(getDownloadFolderPath(), `${yield Auth.MyUserName()}@irfanshadikrishad-anilist-${dataType}-${getFormattedDate()}.json`);
117
+ const path = yield saveToPath(dataType, ".json");
107
118
  yield writeFile(path, jsonData, "utf8");
108
119
  console.log(`\nSaved as JSON successfully.`);
109
120
  open(getDownloadFolderPath());
@@ -116,13 +127,17 @@ function saveJSONasJSON(js0n, dataType) {
116
127
  /**
117
128
  * Export JSON as CSV
118
129
  * @param js0n
119
- * @param dataType (eg: anime/manga)
130
+ * @param dataType (eg: anime|manga)
120
131
  */
121
132
  function saveJSONasCSV(js0n, dataType) {
122
133
  return __awaiter(this, void 0, void 0, function* () {
123
134
  try {
124
- const csvData = parse(js0n);
125
- const path = join(getDownloadFolderPath(), `${yield Auth.MyUserName()}@irfanshadikrishad-anilist-${dataType}-${getFormattedDate()}.csv`);
135
+ const js0n_WTAS = js0n.map((_a) => {
136
+ var { title } = _a, rest = __rest(_a, ["title"]);
137
+ return (Object.assign(Object.assign({}, rest), { title: getTitle(title) }));
138
+ });
139
+ const csvData = Papa.unparse(js0n_WTAS);
140
+ const path = yield saveToPath(dataType, ".csv");
126
141
  yield writeFile(path, csvData, "utf8");
127
142
  console.log(`\nSaved as CSV successfully.`);
128
143
  open(getDownloadFolderPath());
@@ -132,6 +147,20 @@ function saveJSONasCSV(js0n, dataType) {
132
147
  }
133
148
  });
134
149
  }
150
+ function saveJSONasXML(js0n, data_type) {
151
+ return __awaiter(this, void 0, void 0, function* () {
152
+ try {
153
+ const xmlContent = data_type === 0 ? createAnimeListXML(js0n) : createMangaListXML(js0n);
154
+ const path = yield saveToPath(data_type === 0 ? "anime" : "manga", ".xml");
155
+ yield writeFile(path, yield xmlContent, "utf8");
156
+ console.log(`\nGenerated XML for MyAnimeList.`);
157
+ open(getDownloadFolderPath());
158
+ }
159
+ catch (error) {
160
+ console.error(`Error saving XML data:`, error);
161
+ }
162
+ });
163
+ }
135
164
  function listFilesInDownloadFolder() {
136
165
  return __awaiter(this, void 0, void 0, function* () {
137
166
  const downloadFolderPath = getDownloadFolderPath();
@@ -172,12 +201,12 @@ function selectFile(fileType) {
172
201
  }
173
202
  });
174
203
  }
175
- function createAnimeXML(malId, progress, status, episodes, title) {
204
+ function createAnimeXML(malId, progress, status, episodes, title, format) {
176
205
  return `
177
206
  <anime>
178
207
  <series_animedb_id>${malId}</series_animedb_id>
179
208
  <series_title><![CDATA[${title}]]></series_title>
180
- <series_type>""</series_type>
209
+ <series_type>${format}</series_type>
181
210
  <series_episodes>${episodes}</series_episodes>
182
211
  <my_id>0</my_id>
183
212
  <my_watched_episodes>${progress}</my_watched_episodes>
@@ -230,12 +259,14 @@ function createAnimeListXML(mediaWithProgress) {
230
259
  // Filter out anime without malId
231
260
  const filteredMedia = mediaWithProgress.filter((anime) => anime.malId);
232
261
  const xmlEntries = filteredMedia.map((anime) => {
262
+ console.log(anime);
233
263
  const malId = anime.malId;
234
264
  const progress = anime.progress;
235
265
  const episodes = anime.episodes;
236
266
  const title = getTitle(anime.title);
237
267
  const status = statusMap[anime.status];
238
- return createAnimeXML(malId, progress, status, episodes, title);
268
+ const format = anime.format ? anime.format : "";
269
+ return createAnimeXML(malId, progress, status, episodes, title, format);
239
270
  });
240
271
  return `<myanimelist>
241
272
  <myinfo>
@@ -350,4 +381,15 @@ const anidbToanilistMapper = (romanjiName, year, englishName) => __awaiter(void
350
381
  }
351
382
  return null;
352
383
  });
353
- export { anidbToanilistMapper, aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getCurrentPackageVersion, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, selectFile, timestampToTimeAgo, };
384
+ /**
385
+ * Extract the save file path
386
+ * @param data_type - anime|manga
387
+ * @param file_format - save format (eg: .json|.csv)
388
+ * @returns string of file path
389
+ */
390
+ function saveToPath(data_type, file_format) {
391
+ return __awaiter(this, void 0, void 0, function* () {
392
+ return join(getDownloadFolderPath(), `${yield Auth.MyUserName()}@irfanshadikrishad-anilist-${data_type}-${getFormattedDate()}.${file_format}`);
393
+ });
394
+ }
395
+ export { anidbToanilistMapper, aniListEndpoint, createAnimeListXML, createAnimeXML, createMangaListXML, createMangaXML, formatDateObject, getCurrentPackageVersion, getDownloadFolderPath, getFormattedDate, getNextSeasonAndYear, getTitle, redirectUri, removeHtmlAndMarkdown, saveJSONasCSV, saveJSONasJSON, saveJSONasXML, saveToPath, selectFile, timestampToTimeAgo, };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@irfanshadikrishad/anilist",
3
3
  "description": "Minimalist unofficial AniList CLI for Anime and Manga Enthusiasts",
4
4
  "author": "Irfan Shadik Rishad",
5
- "version": "1.2.10",
5
+ "version": "1.2.11",
6
6
  "main": "./bin/index.js",
7
7
  "type": "module",
8
8
  "types": "./bin/index.d.ts",
@@ -54,31 +54,31 @@
54
54
  },
55
55
  "license": "MPL-2.0",
56
56
  "devDependencies": {
57
- "@babel/preset-env": "^7.26.0",
58
- "@eslint/js": "^9.17.0",
57
+ "@babel/preset-env": "^7.26.7",
58
+ "@eslint/js": "^9.19.0",
59
59
  "@types/jest": "^29.5.14",
60
- "@types/json2csv": "^5.0.7",
61
- "@types/node": "^22.10.5",
60
+ "@types/node": "^22.12.0",
61
+ "@types/papaparse": "^5.3.15",
62
62
  "@types/xml2js": "^0.4.14",
63
- "@typescript-eslint/eslint-plugin": "^8.19.0",
64
- "eslint": "^9.17.0",
63
+ "@typescript-eslint/eslint-plugin": "^8.22.0",
64
+ "eslint": "^9.19.0",
65
65
  "globals": "^15.14.0",
66
66
  "jest": "^29.7.0",
67
67
  "prettier": "^3.4.2",
68
68
  "prettier-plugin-organize-imports": "^4.1.0",
69
69
  "ts-jest": "^29.2.5",
70
70
  "ts-node": "^10.9.2",
71
- "typescript": "^5.7.2"
71
+ "typescript": "^5.7.3"
72
72
  },
73
73
  "dependencies": {
74
- "commander": "^13.0.0",
74
+ "commander": "^13.1.0",
75
75
  "fast-xml-parser": "^4.5.1",
76
- "inquirer": "^12.3.0",
77
- "json2csv": "^6.0.0-alpha.2",
76
+ "inquirer": "^12.3.3",
78
77
  "jsonrepair": "^3.11.2",
79
78
  "node-fetch": "^3.3.2",
80
79
  "open": "^10.1.0",
81
- "tiny-spinner": "^2.0.4",
80
+ "papaparse": "^5.5.2",
81
+ "tiny-spinner": "^2.0.5",
82
82
  "xml2js": "^0.6.2"
83
83
  }
84
84
  }