|
| 1 | +import * as fs from "node:fs"; |
| 2 | +import * as path from "node:path"; |
1 | 3 | import * as vscode from "vscode"; |
2 | 4 | import { ItemDetailType, ItemDetails, Items } from "./types/Items"; |
3 | 5 |
|
4 | 6 | export function activate(context: vscode.ExtensionContext) { |
5 | | - console.log("The SPT Dev extension is now active."); |
| 7 | + console.log("The SPT ID Highlighter extension is now active."); |
| 8 | + |
| 9 | + // biome-ignore lint/suspicious/noExplicitAny: <explanation> |
| 10 | + const validateItemDetails = (details: any): details is ItemDetails => { |
| 11 | + const validItemKeys: Array<keyof ItemDetails> = [ |
| 12 | + "Name", |
| 13 | + "ShortName", |
| 14 | + "Type", |
| 15 | + "DetailLink", |
| 16 | + "Parent", |
| 17 | + "ParentID", |
| 18 | + "ParentDetailLink", |
| 19 | + "FleaBlacklisted", |
| 20 | + "QuestItem", |
| 21 | + "Weight", |
| 22 | + "Caliber", |
| 23 | + "Damage", |
| 24 | + "ArmorDamage", |
| 25 | + "PenetrationPower", |
| 26 | + "Currency", |
| 27 | + "UnlockedByDefault", |
| 28 | + "Description", |
| 29 | + "BodyPart", |
| 30 | + "Sides", |
| 31 | + "IntegratedArmorVest", |
| 32 | + "AvailableAsDefault", |
| 33 | + "PrefabPath", |
| 34 | + "Id", |
| 35 | + "AirdropChance", |
| 36 | + "EscapeTimeLimit", |
| 37 | + "Insurance", |
| 38 | + "BossSpawns", |
| 39 | + "Trader", |
| 40 | + "TraderId", |
| 41 | + "TraderLink", |
| 42 | + "QuestType", |
| 43 | + ]; |
| 44 | + return Object.keys(details).every((key) => validItemKeys.includes(key as keyof ItemDetails)); |
| 45 | + }; |
| 46 | + |
| 47 | + const getProjectRoot = (): string => { |
| 48 | + const folders = vscode.workspace.workspaceFolders; |
| 49 | + return folders && folders.length > 0 ? folders[0].uri.fsPath : ""; |
| 50 | + }; |
| 51 | + |
| 52 | + // biome-ignore lint/suspicious/noExplicitAny: <explanation> |
| 53 | + const loadCustomIds = (projectRoot: string): Record<string, any> => { |
| 54 | + const sptidsPath = path.join(projectRoot, ".sptids"); |
| 55 | + if (!fs.existsSync(sptidsPath)) { |
| 56 | + return {}; |
| 57 | + } |
| 58 | + |
| 59 | + try { |
| 60 | + const rawData = fs.readFileSync(sptidsPath, "utf-8"); |
| 61 | + return JSON.parse(rawData); |
| 62 | + } catch (error) { |
| 63 | + console.error(`SPT ID Highlighter: Failed to load .sptids file: ${error}`); |
| 64 | + vscode.window.showErrorMessage("SPT ID Highlighter: The .sptids file is invalid or could not be read."); |
| 65 | + return {}; |
| 66 | + } |
| 67 | + }; |
| 68 | + |
| 69 | + // biome-ignore lint/suspicious/noExplicitAny: <explanation> |
| 70 | + const mergeCustomItems = (baseData: Items, customData: Record<string, any>, lang: string): Items => { |
| 71 | + const mergedData = { ...baseData }; |
| 72 | + |
| 73 | + for (const [id, localizedData] of Object.entries(customData)) { |
| 74 | + if (localizedData[lang]) { |
| 75 | + const customDetails = localizedData[lang]; |
| 76 | + if (validateItemDetails(customDetails)) { |
| 77 | + mergedData[id] = { |
| 78 | + ...mergedData[id], |
| 79 | + ...customDetails, |
| 80 | + }; |
| 81 | + } else { |
| 82 | + console.warn(`SPT ID Highlighter: Invalid item properties for ID ${id} in .sptids.`); |
| 83 | + vscode.window.showWarningMessage( |
| 84 | + `SPT ID Highlighter: Invalid item properties for ID ${id} in .sptids.`, |
| 85 | + ); |
| 86 | + } |
| 87 | + } |
| 88 | + } |
| 89 | + |
| 90 | + return mergedData; |
| 91 | + }; |
6 | 92 |
|
7 | 93 | const loadItemsData = (lang: string): Items => { |
8 | 94 | try { |
9 | | - return require(`./database/${lang}.json`); |
| 95 | + const baseData = require(`./database/${lang}.json`); |
| 96 | + const projectRoot = getProjectRoot(); |
| 97 | + const customData = loadCustomIds(projectRoot); |
| 98 | + return mergeCustomItems(baseData, customData, lang); |
10 | 99 | } catch (error) { |
11 | | - console.error(`Failed to load language file: ${lang}.json`, error); |
12 | | - vscode.window.showErrorMessage(`Failed to load language data for ${lang}. Falling back to English.`); |
13 | | - return require("./database/en.json"); // Fallback to English |
| 100 | + console.error(`SPT ID Highlighter: Failed to load language file: ${lang}.json`, error); |
| 101 | + vscode.window.showErrorMessage( |
| 102 | + `SPT ID Highlighter: Failed to load language data for ${lang}. Falling back to English.`, |
| 103 | + ); |
| 104 | + return require("./database/en.json"); |
14 | 105 | } |
15 | 106 | }; |
16 | 107 |
|
17 | 108 | const loadTranslations = (lang: string): Record<string, string> => { |
18 | 109 | try { |
19 | 110 | return require(`./translations/${lang}.json`); |
20 | 111 | } catch (error) { |
21 | | - console.error(`Failed to load translation file: ${lang}.json`, error); |
22 | | - vscode.window.showErrorMessage(`Failed to load translations for ${lang}. Falling back to English.`); |
| 112 | + console.error(`SPT ID Highlighter: Failed to load translation file: ${lang}.json`, error); |
| 113 | + vscode.window.showErrorMessage( |
| 114 | + `SPT ID Highlighter: Failed to load translations for ${lang}. Falling back to English.`, |
| 115 | + ); |
23 | 116 | return require("./translations/en.json"); // Fallback to English |
24 | 117 | } |
25 | 118 | }; |
26 | 119 |
|
27 | | - let configuration = vscode.workspace.getConfiguration("spt-dev"); |
| 120 | + let configuration = vscode.workspace.getConfiguration("spt-id-highlighter"); |
28 | 121 | let language = configuration.get("language", "en"); |
29 | 122 | let itemsData: Items = loadItemsData(language); |
30 | 123 | let translations: Record<string, string> = loadTranslations(language); |
@@ -63,10 +156,42 @@ export function activate(context: vscode.ExtensionContext) { |
63 | 156 | updateDecorations(); |
64 | 157 | } |
65 | 158 |
|
| 159 | + const projectRoot = getProjectRoot(); |
| 160 | + if (fs.existsSync(projectRoot)) { |
| 161 | + const watcher = fs.watch(projectRoot, (eventType, filename) => { |
| 162 | + if (filename === ".sptids") { |
| 163 | + const sptidsPath = path.join(projectRoot, ".sptids"); |
| 164 | + if (eventType === "rename") { |
| 165 | + // File created or deleted |
| 166 | + if (fs.existsSync(sptidsPath)) { |
| 167 | + console.log("SPT ID Highlighter: Detected .sptids creation. Reloading..."); |
| 168 | + itemsData = loadItemsData(language); // Reload items data |
| 169 | + updateDecorations(); // Update decorations |
| 170 | + vscode.window.showInformationMessage("SPT ID Highlighter: Successfully loaded custom items."); |
| 171 | + } else { |
| 172 | + console.log("SPT ID Highlighter: Detected .sptids file deletion."); |
| 173 | + itemsData = loadItemsData(language); // Reload without custom items |
| 174 | + updateDecorations(); // Update decorations |
| 175 | + vscode.window.showWarningMessage("SPT ID Highlighter: Successfully unloaded custom items."); |
| 176 | + } |
| 177 | + } else if (eventType === "change") { |
| 178 | + // File updated |
| 179 | + console.log("SPT ID Highlighter: Detected .sptids file change. Reloading..."); |
| 180 | + itemsData = loadItemsData(language); // Reload items data |
| 181 | + updateDecorations(); // Update decorations |
| 182 | + vscode.window.showInformationMessage("SPT ID Highlighter: Successfully reloaded custom items."); |
| 183 | + } |
| 184 | + } |
| 185 | + }); |
| 186 | + context.subscriptions.push({ |
| 187 | + dispose: () => watcher.close(), |
| 188 | + }); |
| 189 | + } |
| 190 | + |
66 | 191 | context.subscriptions.push( |
67 | 192 | vscode.workspace.onDidChangeConfiguration((e) => { |
68 | | - if (e.affectsConfiguration("spt-dev.language")) { |
69 | | - configuration = vscode.workspace.getConfiguration("spt-dev"); |
| 193 | + if (e.affectsConfiguration("spt-id-highlighter.language")) { |
| 194 | + configuration = vscode.workspace.getConfiguration("spt-id-highlighter"); |
70 | 195 | language = configuration.get("language", "en"); |
71 | 196 | itemsData = loadItemsData(language); |
72 | 197 | translations = loadTranslations(language); |
|
0 commit comments