diff --git a/eslint.config.js b/eslint.config.js index 8ef2c4e..868d954 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -244,6 +244,7 @@ module.exports = [ } }, files: ["vscExtension/**/*.js", "eslint.config.js", "minify.js"], + ignores: ["vscExtension/out/*.js"], plugins: { unicorn, sonarjs, diff --git a/vscExtension/.vscodeignore b/vscExtension/.vscodeignore new file mode 100644 index 0000000..10cb6db --- /dev/null +++ b/vscExtension/.vscodeignore @@ -0,0 +1,2 @@ +build.js +src/** diff --git a/vscExtension/build.js b/vscExtension/build.js index eeabb5e..1cc870b 100644 --- a/vscExtension/build.js +++ b/vscExtension/build.js @@ -1,9 +1,15 @@ const fs = require("node:fs").promises +const path = require("node:path") const main = async () => { - const extension = await fs.readFile("./src/extension.js", "utf8") + let extension = await fs.readFile("./src/extension.js", "utf8") //const packAnalyzer = await fs.readFile("./src/script.js", "utf8") + for await (const match of extension.match(/{DPICON\|\w+?}/g)) { + const icon = await fs.readFile(path.join(__dirname, "dpIcons", match.replace("{DPICON|", "").replace("}", "") + ".png")) + extension = extension.replace(match, Buffer.from(icon).toString("base64")) + } + await fs.writeFile("./out/extension.js", /*packAnalyzer.toString() + "\n".repeat(3) +*/ extension.toString()) } main() diff --git a/vscExtension/dpIcons/README.md b/vscExtension/dpIcons/README.md new file mode 100644 index 0000000..199181c --- /dev/null +++ b/vscExtension/dpIcons/README.md @@ -0,0 +1,5 @@ +All icons in this folder are from the [**Datapack Icons** extension](https://marketplace.visualstudio.com/items?itemName=SuperAnt.mc-dp-icons) created by SuperAnt_, bth123 and amandin. + +They have given permission to use these icons in this extension. + +Please see their [GitHub repository](https://github.com/SuperAnt220/mc-dp-icons) and [license](https://github.com/SuperAnt220/mc-dp-icons/blob/main/LICENSE.txt) for more information. diff --git a/vscExtension/dpIcons/assets.png b/vscExtension/dpIcons/assets.png new file mode 100644 index 0000000..66fa70a Binary files /dev/null and b/vscExtension/dpIcons/assets.png differ diff --git a/vscExtension/dpIcons/atlases.png b/vscExtension/dpIcons/atlases.png new file mode 100644 index 0000000..9c88162 Binary files /dev/null and b/vscExtension/dpIcons/atlases.png differ diff --git a/vscExtension/dpIcons/blockstates.png b/vscExtension/dpIcons/blockstates.png new file mode 100644 index 0000000..3dae132 Binary files /dev/null and b/vscExtension/dpIcons/blockstates.png differ diff --git a/vscExtension/dpIcons/data.png b/vscExtension/dpIcons/data.png new file mode 100644 index 0000000..7e6090a Binary files /dev/null and b/vscExtension/dpIcons/data.png differ diff --git a/vscExtension/dpIcons/folder.png b/vscExtension/dpIcons/folder.png new file mode 100644 index 0000000..879a79b Binary files /dev/null and b/vscExtension/dpIcons/folder.png differ diff --git a/vscExtension/dpIcons/font.png b/vscExtension/dpIcons/font.png new file mode 100644 index 0000000..859c246 Binary files /dev/null and b/vscExtension/dpIcons/font.png differ diff --git a/vscExtension/dpIcons/functions.png b/vscExtension/dpIcons/functions.png new file mode 100644 index 0000000..78a6b64 Binary files /dev/null and b/vscExtension/dpIcons/functions.png differ diff --git a/vscExtension/dpIcons/lang.png b/vscExtension/dpIcons/lang.png new file mode 100644 index 0000000..72933ce Binary files /dev/null and b/vscExtension/dpIcons/lang.png differ diff --git a/vscExtension/dpIcons/mcfunction.png b/vscExtension/dpIcons/mcfunction.png new file mode 100644 index 0000000..6ce5f44 Binary files /dev/null and b/vscExtension/dpIcons/mcfunction.png differ diff --git a/vscExtension/dpIcons/mcfunction_load.png b/vscExtension/dpIcons/mcfunction_load.png new file mode 100644 index 0000000..489da15 Binary files /dev/null and b/vscExtension/dpIcons/mcfunction_load.png differ diff --git a/vscExtension/dpIcons/md.png b/vscExtension/dpIcons/md.png new file mode 100644 index 0000000..c3c1bc7 Binary files /dev/null and b/vscExtension/dpIcons/md.png differ diff --git a/vscExtension/dpIcons/misc.png b/vscExtension/dpIcons/misc.png new file mode 100644 index 0000000..96c5aeb Binary files /dev/null and b/vscExtension/dpIcons/misc.png differ diff --git a/vscExtension/dpIcons/models.png b/vscExtension/dpIcons/models.png new file mode 100644 index 0000000..260183a Binary files /dev/null and b/vscExtension/dpIcons/models.png differ diff --git a/vscExtension/dpIcons/namespace.png b/vscExtension/dpIcons/namespace.png new file mode 100644 index 0000000..a935cc2 Binary files /dev/null and b/vscExtension/dpIcons/namespace.png differ diff --git a/vscExtension/dpIcons/particles.png b/vscExtension/dpIcons/particles.png new file mode 100644 index 0000000..2676110 Binary files /dev/null and b/vscExtension/dpIcons/particles.png differ diff --git a/vscExtension/dpIcons/shaders.png b/vscExtension/dpIcons/shaders.png new file mode 100644 index 0000000..aecfa96 Binary files /dev/null and b/vscExtension/dpIcons/shaders.png differ diff --git a/vscExtension/dpIcons/sounds.png b/vscExtension/dpIcons/sounds.png new file mode 100644 index 0000000..d526ce0 Binary files /dev/null and b/vscExtension/dpIcons/sounds.png differ diff --git a/vscExtension/dpIcons/src_folder.png b/vscExtension/dpIcons/src_folder.png new file mode 100644 index 0000000..28a7ff4 Binary files /dev/null and b/vscExtension/dpIcons/src_folder.png differ diff --git a/vscExtension/dpIcons/tags.png b/vscExtension/dpIcons/tags.png new file mode 100644 index 0000000..6d32d28 Binary files /dev/null and b/vscExtension/dpIcons/tags.png differ diff --git a/vscExtension/dpIcons/texts.png b/vscExtension/dpIcons/texts.png new file mode 100644 index 0000000..02436c2 Binary files /dev/null and b/vscExtension/dpIcons/texts.png differ diff --git a/vscExtension/dpIcons/textures.png b/vscExtension/dpIcons/textures.png new file mode 100644 index 0000000..79c63e9 Binary files /dev/null and b/vscExtension/dpIcons/textures.png differ diff --git a/vscExtension/package.json b/vscExtension/package.json index f36a8c8..88e7396 100644 --- a/vscExtension/package.json +++ b/vscExtension/package.json @@ -33,11 +33,7 @@ "commands": [ { "command": "packAnalyzer.refresh", - "title": "Refresh", - "icon": { - "light": "resources/light/refresh.svg", - "dark": "resources/dark/refresh.svg" - } + "title": "Refresh" } ], "menus": { diff --git a/vscExtension/src/extension.js b/vscExtension/src/extension.js index 1651898..0c3b768 100644 --- a/vscExtension/src/extension.js +++ b/vscExtension/src/extension.js @@ -277,9 +277,6 @@ async function processEntries(entries) { } async function mainScan() { - const uncalledFunctions = dpExclusive.functions.filter(funcName => !dpExclusive.functionCalls.some(func => func.target == funcName)) - const missingFunctions = [...new Set(dpExclusive.functionCalls.filter(func => !dpExclusive.functions.includes(func.target)).map(func => func.target))] - let html = (packImages.length > 0 ? "
" + packImages.map(img => "") + "
" : "") + (packFiles.length > 0 ? "" + (rpMode ? "Resource" : "Data") + "pack" + (packFiles.length == 1 ? "" : "s") + " found:
" + @@ -330,12 +327,6 @@ async function mainScan() { : "") + (packFiles.length == 0 && (filetypes.fsh || filetypes.vsh || filetypes.xcf || filetypes.glsl) ? "Shader found
" : "") + - (Object.keys(commands).length > 0 ? - "Total amount of commands: " + localize(Object.keys(commands).reduce((a, b) => a + commands[b], 0)) + "
" + - "Unique command names: " + localize(Object.keys(commands).length) + "
" - : "") + - (comments > 0 ? "Comments: " + localize(comments) + "
" : "") + - (empty > 0 ? "Empty lines: " + localize(empty) + "
" : "") + "Pack file types found:
" + Object.keys(filetypes).sort((a, b) => filetypes[b] - filetypes[a]).map(type => "." + type + ": " + localize(filetypes[type]) + "
").join("") + (Object.keys(filetypesOther).length > 0 ? @@ -344,16 +335,6 @@ async function mainScan() { Object.keys(filetypesOther).sort((a, b) => filetypesOther[b] - filetypesOther[a]).map(type => "" + type + ": " + localize(filetypesOther[type]) + "
").join("") + "
" : "") + - (uncalledFunctions.length > 0 ? - "Uncalled functions:
" + - uncalledFunctions.map(func => "" + func + "
").join("") + - "
" - : "") + - (missingFunctions.length > 0 ? - "Missing functions:
" + - missingFunctions.map(func => "" + func + "
").join("") + - "
" - : "") + (emptyFiles.length > 0 ? "Empty files:
" + emptyFiles.map(func => "" + func + "
").join("") + @@ -396,11 +377,19 @@ const collapsible = new Set([ "cmdsBehindMacros", "cmdsBehindReturn", - "folders", "tags", - "selectors" + "selectors", + + "uncalledFunctions", + "missingFunctions" ]) +const iconUrl = (icon = "") => + vscode.Uri.from({ + scheme: "data", + path: "image/png;base64," + icon + "" + }) + class PackAnalyzer { constructor() { this._onDidChangeTreeData = new vscode.EventEmitter() @@ -489,42 +478,85 @@ class PackAnalyzer { getTreeItem(element) { log("getTreeItem: " + JSON.stringify(element)) - let label = element.item - const treeItem = new vscode.TreeItem(label) - - if (element.item == "files") label = "Scanned files: " + files - else if (element.item == "error") label = "Scanning errors: " + error - else if (element.item == "rpMode") label = "Resource pack mode: " + (rpMode ? "enabled" : "disabled") - - else if (element.item == "dpExclusive") label = "Data pack" - else if (element.parent == "folders") label = element.item + ": " + dpExclusive.folders[element.item] - else if (element.parent == "tags") label = element.item + ": " + dpExclusive.tags[element.item] - else if (element.item == "scoreboards") label = "Scoreboards: " + dpExclusive.scoreboards - else if (element.item == "selectors") label = "Selectors: " + Object.keys(dpExclusive.selectors).length - else if (element.parent == "selectors") label = "@" + element.item + ": " + dpExclusive.selectors[element.item] - - else if (element.item == "rpExclusive") label = "Resource pack" - else if (element.parent == "rpExclusive") label = element.item + ": " + rpExclusive[element.item] - - else if (element.item == "filetypes") label = "File types: " + Object.keys(filetypes).length - else if (element.parent == "filetypes") label = "." + element.item + ": " + filetypes[element.item] - else if (element.item == "filetypesOther") label = "Non-pack file types: " + Object.keys(filetypesOther).length - else if (element.parent == "filetypesOther") label = element.item + ": " + filetypesOther[element.item] - - else if (element.item == "commands") label = "Commands: " + Object.keys(commands).length - else if (element.parent == "commands") { - label = element.item + ": " + commands[element.item] - if (cmdsBehindExecute[element.item]) treeItem.description = "(" + cmdsBehindExecute[element.item] + " behind execute)" - } else if (element.item == "cmdsBehindMacros") label = "Commands behind macros: " + Object.keys(cmdsBehindMacros).length - else if (element.item == "cmdsBehindReturn") label = "Commands behind return: " + Object.keys(cmdsBehindReturn).length - - else if (element.item == "comments") label = "Comments: " + comments - else if (element.item == "empty") label = "Empty lines: " + empty - else if (element.item == "emptyFiles") label = "Empty files: " + emptyFiles.length - - treeItem.label = label + const treeItem = new vscode.TreeItem(element.item) + treeItem.iconPath = iconUrl("{DPICON|namespace}") if (collapsible.has(element.item)) treeItem.collapsibleState = vscode.TreeItemCollapsibleState.Collapsed + if (element.item == "files") treeItem.label = "Scanned files: " + localize(files) + else if (element.item == "error") treeItem.label = "Scanning errors: " + localize(error) + else if (element.item == "rpMode") treeItem.label = "Resource pack mode: " + (rpMode ? "enabled" : "disabled") + + else if (element.item == "dpExclusive") { + treeItem.label = "Data pack" + treeItem.iconPath = iconUrl("{DPICON|mcfunction}") + } else if (element.item == "tags") { + treeItem.label = "Tags" + treeItem.description = "(" + localize(Object.values(dpExclusive.tags).reduce((a, b) => a + b)) + " total, " + localize(Object.keys(dpExclusive.tags).length) + " unique)" + treeItem.iconPath = iconUrl("{DPICON|tags}") + } else if (element.parent == "tags") { + treeItem.label = element.item + ": " + localize(dpExclusive.tags[element.item]) + treeItem.iconPath = iconUrl("{DPICON|tags}") + } else if (element.item == "scoreboards") treeItem.label = "Scoreboards: " + localize(dpExclusive.scoreboards) + else if (element.item == "selectors") { + treeItem.label = "Selectors" + treeItem.iconPath = iconUrl("{DPICON|mcfunction}") + } else if (element.parent == "selectors") { + treeItem.label = "@" + element.item + ": " + localize(dpExclusive.selectors[element.item]) + treeItem.iconPath = iconUrl("{DPICON|mcfunction}") + } else if (element.item == "rpExclusive") { + treeItem.label = "Resource pack" + treeItem.iconPath = iconUrl("{DPICON|assets}") + } else if (element.parent == "rpExclusive") { + treeItem.label = element.item + ": " + localize(rpExclusive[element.item]) + + // Must be hardcoded due to static replacement in vscExtension/build.js + if (element.item == "atlases") treeItem.iconPath = iconUrl("{DPICON|atlases}") + else if (element.item == "blockstates") treeItem.iconPath = iconUrl("{DPICON|blockstates}") + else if (element.item == "font") treeItem.iconPath = iconUrl("{DPICON|font}") + else if (element.item == "lang") treeItem.iconPath = iconUrl("{DPICON|lang}") + else if (element.item == "models") treeItem.iconPath = iconUrl("{DPICON|models}") + else if (element.item == "particles") treeItem.iconPath = iconUrl("{DPICON|particles}") + else if (element.item == "shaders") treeItem.iconPath = iconUrl("{DPICON|shaders}") + else if (element.item == "sounds") treeItem.iconPath = iconUrl("{DPICON|sounds}") + else if (element.item == "texts") treeItem.iconPath = iconUrl("{DPICON|texts}") + else if (element.item == "textures") treeItem.iconPath = iconUrl("{DPICON|textures}") + } else if (element.item == "filetypes") { + treeItem.label = "Files" + treeItem.description = "(parsed only; " + localize(Object.values(filetypes).reduce((a, b) => a + b)) + " total, " + localize(Object.keys(filetypes).length) + " unique)" + treeItem.iconPath = iconUrl("{DPICON|folder}") + } else if (element.parent == "filetypes") treeItem.label = "." + element.item + ": " + localize(filetypes[element.item]) + + else if (element.item == "commands") { + treeItem.label = "Commands" + treeItem.description = "(" + localize(Object.values(commands).reduce((a, b) => a + b)) + " total, " + localize(Object.keys(commands).length) + " unique)" + } else if (element.parent == "commands") { + treeItem.label = element.item + ": " + localize(commands[element.item]) + if (cmdsBehindExecute[element.item]) { + treeItem.description = (element.item == "execute" ? "⚠️ " : "") + "(" + localize(cmdsBehindExecute[element.item]) + " behind execute)" + if (element.item == "execute") treeItem.tooltip = "⚠️ (\"... run execute ...\" equals \"... ...\")" + } + } else if (element.item == "cmdsBehindMacros") treeItem.label = "Commands behind macros: " + localize(Object.keys(cmdsBehindMacros).length) + else if (element.parent == "cmdsBehindMacros") treeItem.label = element.item + ": " + localize(cmdsBehindMacros[element.item]) + else if (element.item == "cmdsBehindReturn") treeItem.label = "Commands behind return: " + localize(Object.keys(cmdsBehindReturn).length) + else if (element.parent == "cmdsBehindReturn") treeItem.label = element.item + ": " + localize(cmdsBehindReturn[element.item]) + + else if (element.item == "comments") { + treeItem.label = "Comments: " + localize(comments) + treeItem.iconPath = iconUrl("{DPICON|md}") + } else if (element.item == "empty") { + treeItem.label = "Empty lines: " + localize(empty) + treeItem.iconPath = iconUrl("{DPICON|misc}") + } else if (element.item == "emptyFiles") { + treeItem.label = "Empty files: " + localize(emptyFiles.length) + treeItem.iconPath = iconUrl("{DPICON|misc}") + } else if (element.item == "uncalledFunctions") { + treeItem.label = "Uncalled functions: " + localize(dpExclusive.uncalledFunctions.length) + treeItem.iconPath = iconUrl("{DPICON|mcfunction}") + } else if (element.item == "missingFunctions") { + treeItem.label = "Missing functions: " + localize(dpExclusive.missingFunctions.length) + treeItem.iconPath = iconUrl("{DPICON|mcfunction}") + } + return treeItem } @@ -534,26 +566,26 @@ class PackAnalyzer { if (element) { const item = element.item if (item == "dpExclusive") return [ - Object.keys(dpExclusive.folders).reduce((a, b) => a + dpExclusive.folders[b], 0) > 0 ? "folders" : void 0, Object.keys(dpExclusive.tags).reduce((a, b) => a + dpExclusive.tags[b], 0) > 0 ? "tags" : void 0, dpExclusive.scoreboards > 0 ? "scoreboards" : void 0, Object.keys(dpExclusive.selectors).reduce((a, b) => a + dpExclusive.selectors[b], 0) > 0 ? "selectors" : void 0, - "uncalledFunctions", - "missingFunctions" + dpExclusive.uncalledFunctions.length > 0 ? "uncalledFunctions" : void 0, + dpExclusive.missingFunctions.length > 0 ? "missingFunctions" : void 0 ].filter(Boolean).map(child => ({item: child, parent: item})) - if (item == "folders") return Object.keys(dpExclusive.folders).filter(key => dpExclusive.folders[key] > 0).map(child => ({item: child, parent: item})) if (item == "tags") return Object.keys(dpExclusive.tags).filter(key => dpExclusive.tags[key] > 0).map(child => ({item: child, parent: item})) if (item == "selectors") return Object.keys(dpExclusive.selectors).filter(key => dpExclusive.selectors[key] > 0).map(child => ({item: child, parent: item})) if (item == "rpExclusive") return Object.keys(rpExclusive).filter(key => rpExclusive[key] > 0).map(child => ({item: child, parent: item})) if (item == "filetypes") return Object.keys(filetypes).map(child => ({item: child, parent: item})) - if (item == "filetypesOther") return Object.keys(filetypesOther).map(child => ({item: child, parent: item})) if (item == "commands") return Object.keys(commands).map(child => ({item: child, parent: item})) if (item == "cmdsBehindMacros") return Object.keys(cmdsBehindMacros).map(child => ({item: child, parent: item})) if (item == "cmdsBehindReturn") return Object.keys(cmdsBehindReturn).map(child => ({item: child, parent: item})) + + if (item == "missingFunctions") return dpExclusive.missingFunctions.map(child => ({item: child, parent: item})) + if (item == "uncalledFunctions") return dpExclusive.uncalledFunctions.map(child => ({item: child, parent: item})) } const fileList = await vscode.workspace.findFiles("**/*") @@ -569,6 +601,9 @@ class PackAnalyzer { return [] } + dpExclusive.uncalledFunctions = dpExclusive.functions.filter(funcName => !dpExclusive.functionCalls.some(func => func.target == funcName)) + dpExclusive.missingFunctions = [...new Set(dpExclusive.functionCalls.filter(func => !dpExclusive.functions.includes(func.target)).map(func => func.target))] + return [ "files", error > 0 ? "error" : void 0, @@ -576,9 +611,7 @@ class PackAnalyzer { rpMode ? void 0 : "dpExclusive", rpMode ? "rpExclusive" : void 0, - Object.keys(filetypes).length > 0 ? "filetypes" : void 0, - Object.keys(filetypesOther).length > 0 ? "filetypesOther" : void 0, Object.keys(commands).length > 0 ? "commands" : void 0, Object.keys(cmdsBehindMacros).length > 0 ? "cmdsBehindMacros" : void 0,