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,