-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
186 lines (159 loc) · 5.64 KB
/
index.js
File metadata and controls
186 lines (159 loc) · 5.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/usr/bin/env node
import fs from "fs";
import chalk from "chalk";
import { input } from "@inquirer/prompts";
// Note: this does not work with Prettier. Uncomment line 16 and comment out the following line when developing
import stackSizes from "./itemStacks.json" with { type: "json" };
/**
* The amount of items to display at a time.
*/
const ITEMS_PER_PAGE = 5;
// Uncomment this line when developing so that it works with Prettier:
// const stackSizes = JSON.parse(fs.readFileSync("itemStacks.json", { encoding: "utf-8" }));
/**
* Gets the custom stack size of the block/item, or 64 by default.
*
* @param {string} itemName The name of the block or item.
* @returns The number that the block/item can stack to.
*/
const getStackSize = (itemName) => stackSizes[itemName.toLowerCase()] || stackSizes["default"];
/**
* Calculates the stacks, items, and shulker boxes needed for an item.
*
* @param {number} total The total amount of the specific block/item required for the build.
* @param {string} itemName The name of the item, for finding the stack limit.
* @returns An object containing the stacks, items, and shulker boxes.
*/
const calculateStacksAndItems = (total, itemName) => {
const stackSize = getStackSize(itemName);
const stacks = Math.floor(total / stackSize);
const items = total % stackSize;
const shulkerBoxes = Math.floor(stacks / 27);
const remainingStacks = stacks - shulkerBoxes * 27;
return { stacks: remainingStacks, items, shulkerBoxes };
};
/**
* Display the items in the table, showing shulker boxes before stacks.
*
* @param {[ { Item: string, Shulkerboxes?: number, Stacks: number, Items: number } ]} data An array of nested objects containing information about each item.
*/
const displayItems = async (data) => {
try {
let currentIndex = 0;
while (currentIndex < data.length) {
const pageData = data.slice(currentIndex, currentIndex + ITEMS_PER_PAGE);
console.log(
"\n" +
chalk.green.bold("Item".padEnd(25)) +
" | " +
chalk.magenta.bold("Shulkers".padEnd(10)) +
" | " +
chalk.cyan.bold("Stacks".padEnd(10)) +
" | " +
chalk.yellow.bold("Items".padEnd(10))
);
console.log(chalk.gray("-".repeat(65)));
pageData.forEach((row) => {
const item = row["Item"] || "N/A";
const shulkers = String(row["Shulkerboxes"] ?? 0);
const stacks = row["Stacks"] || "0";
const items = row["Items"] || "0";
console.log(
chalk.magenta(item.padEnd(25)) +
" | " +
chalk.green(shulkers.padStart(10)) +
" | " +
chalk.blue(String(stacks).padStart(10)) +
" | " +
chalk.red(String(items).padStart(10))
);
});
console.log();
const continueResponse = await input({
message: "Press Enter to continue or type 'exit' to stop:",
});
if (continueResponse.toLowerCase() === "exit") process.exit(0);
currentIndex += ITEMS_PER_PAGE;
}
console.log();
await input({
message: chalk.green("End of list; press Enter to continue..."),
});
} catch (err) {
if (err.name === "ExitPromptError") {
process.exit(1);
}
}
};
/**
* Convert strings containing numbers into numbers and removes double quotes surrounding strings.
*
* @param {string | any} value The value to convert.
* @returns The converted value.
*/
const convertValue = (value) => {
// Remove quotes around values
value = value.replace(/^"(.*)"$/, "$1");
// Check if the value is a number and convert
if (!isNaN(value) && value.trim() !== "") return parseFloat(value);
return value;
};
/**
* Prompts the user to enter the CSV filename.
*
* @returns The name and location of the CSV file.
*/
const getCSVFilename = async () => {
try {
const csvFilename = await input({
message: "Enter the filename of the CSV file:",
default: "list.csv",
required: true,
validate: (value) => {
if (!fs.existsSync(value)) return false;
else return true;
},
});
return csvFilename;
} catch (err) {
if (err.name === "ExitPromptError") {
process.exit(1);
}
}
};
const csvFilename = await getCSVFilename();
const data = fs.readFileSync(csvFilename, "utf8");
// Remove any \r characters
const cleanedData = data.replace(/\r/g, "");
// Split data into lines (rows)
const lines = cleanedData.split("\n");
const headers = lines[0].split(",");
const results = [];
// Process each line of CSV data (skip the first line since it's the header)
for (let i = 1; i < lines.length; i++) {
const row = lines[i].split(","); // Split each row into columns
if (row.length === headers.length) {
const rowObject = {};
for (let j = 0; j < headers.length; j++) {
// Clean the key and the value (remove quotes)
const cleanedHeader = headers[j].replace(/^"(.*)"$/, "$1");
const cleanedValue = convertValue(row[j]);
rowObject[cleanedHeader] = cleanedValue;
}
delete rowObject["Missing"];
delete rowObject["Available"];
// Replace 'Total' with Stacks, Items, and Shulkerboxes
if (rowObject["Total"]) {
const { stacks, items, shulkerBoxes } = calculateStacksAndItems(
rowObject["Total"],
rowObject["Item"]
);
rowObject["Stacks"] = stacks;
rowObject["Items"] = items;
rowObject["Shulkerboxes"] = shulkerBoxes;
delete rowObject["Total"];
}
results.push(rowObject);
}
}
displayItems(results);