diff --git a/CHANGELOG.md b/CHANGELOG.md index 247d026..877a293 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Minor + +- Added vendors.json mapping vendors to models and platformio targets +- Refactored targets.ts to use vendors.json and architecture-hierarchy.json instead of hardware-list.json +- Updated architecture-hierarchy.json generation to use actual PlatformIO environment names (removed normalization) +- Removed normalization from lib/utils.ts since all inputs now use standardized PlatformIO names + ### Patch - Fix Convex server functions being imported in browser by moving ArtifactType enum to client-safe location diff --git a/constants/architecture-hierarchy.json b/constants/architecture-hierarchy.json index 6cf6930..d28be91 100644 --- a/constants/architecture-hierarchy.json +++ b/constants/architecture-hierarchy.json @@ -1,210 +1,210 @@ { - "betafpv2400txmicro": "esp32", - "betafpv900txnano": "esp32", + "betafpv_2400_tx_micro": "esp32", + "betafpv_900_tx_nano": "esp32", "chatter2": "esp32", - "9m2ibraprsloratracker": "esp32", - "meshtasticdrdev": "esp32", + "9m2ibr_aprs_lora_tracker": "esp32", + "meshtastic-dr-dev": "esp32", "hydra": "esp32", - "meshtasticdiyv1": "esp32", - "meshtasticdiyv11": "esp32", - "hackerboxesesp32io": "esp32", - "heltecv1": "esp32", - "heltecv20": "esp32", - "heltecv21": "esp32", - "heltecwirelessbridge": "esp32", - "heltecwslv21": "esp32", - "m5stackcore": "esp32", - "m5stackcoreink": "esp32", - "nanog1": "esp32", - "nanog1explorer": "esp32", - "radiomaster900bandit": "esp32", - "radiomaster900banditmicro": "esp32", - "radiomaster900banditnano": "esp32", + "meshtastic-diy-v1": "esp32", + "meshtastic-diy-v1_1": "esp32", + "hackerboxes-esp32-io": "esp32", + "heltec-v1": "esp32", + "heltec-v2_0": "esp32", + "heltec-v2_1": "esp32", + "heltec-wireless-bridge": "esp32", + "heltec-wsl-v2_1": "esp32", + "m5stack-core": "esp32", + "m5stack-coreink": "esp32", + "nano-g1": "esp32", + "nano-g1-explorer": "esp32", + "radiomaster_900_bandit": "esp32", + "radiomaster_900_bandit_micro": "esp32", + "radiomaster_900_bandit_nano": "esp32", "rak11200": "esp32", - "stationg1": "esp32", + "station-g1": "esp32", "tbeam": "esp32", - "tbeamdisplayshield": "tbeam", - "tbeam07": "esp32", - "tlorav1": "esp32", - "tlorav13": "esp32", - "tlorav2": "esp32", - "tlorav2116": "esp32", - "sugarcube": "tlorav2116", - "tlorav2116tcxo": "esp32", - "tlorav2118": "esp32", - "tlorav330tcxo": "esp32", + "tbeam-displayshield": "tbeam", + "tbeam0_7": "esp32", + "tlora-v1": "esp32", + "tlora_v1_3": "esp32", + "tlora-v2": "esp32", + "tlora-v2-1-1_6": "esp32", + "sugarcube": "tlora-v2-1-1_6", + "tlora-v2-1-1_6-tcxo": "esp32", + "tlora-v2-1-1_8": "esp32", + "tlora-v3-3-0-tcxo": "esp32", "trackerd": "esp32", "wiphone": "esp32", - "aic3": "esp32c3", - "esp32c3supermini": "esp32c3", - "esp32c3base": "esp32", - "hackerboxesesp32c3oled": "esp32c3", - "heltecht62esp32c3sx1262": "esp32c3", - "heltechru3601": "esp32c3", - "m5stackstampc3": "esp32c3", - "esp32c6base": "esp32", - "m5stackunitc6l": "esp32c6", - "tlorac6": "esp32c6", - "esp32s2base": "esp32", - "nuggets2lora": "esp32s2", - "CDEBYTEEoRaS3": "esp32s3", - "EBYTEESP32S3": "esp32s3", - "thinknodem2": "esp32s3", - "thinknodem5": "esp32s3", - "bpipicowesp32s3": "esp32s3", - "crowpanelesp32s35epaper": "esp32s3", - "crowpanelesp32s34epaper": "esp32s3", - "crowpanelesp32s32epaper": "esp32s3", - "myesp32s3diyeink": "esp32s3", - "myesp32s3diyoled": "esp32s3", - "tenergys3e22": "esp32s3", - "dreamcatcher2206": "esp32s3", - "crowpanelbase": "crowpanel", - "elecrowadv2428tft": "crowpanelsmallesp32s3base", - "elecrowadv35tft": "crowpanelsmallesp32s3base", - "elecrowadv1435070tft": "crowpanellargeesp32s3base", - "ESP32S3Pico": "esp32s3", - "esp32s3base": "esp32", - "hackadaycommunicator": "esp32s3", - "helteccapsulesensorv3": "esp32s3", - "heltecsensorhub": "esp32s3", - "heltecv3": "esp32s3", - "heltecv4base": "esp32s3", - "heltecv4": "heltecv4base", - "heltecv4tft": "heltecv4base", - "heltecvisionmastere213": "esp32s3", - "heltecvisionmastere213inkhud": "esp32s3", - "heltecvisionmastere290": "esp32s3", - "heltecvisionmastere290inkhud": "esp32s3", - "heltecvisionmastert190": "esp32s3", - "heltecwirelesspaper": "esp32s3", - "heltecwirelesspaperinkhud": "esp32s3", - "heltecwirelesspaperv10": "esp32s3", - "heltecwirelesstracker": "esp32s3", - "heltecwirelesstrackerV10": "esp32s3", - "heltecwirelesstrackerv2": "esp32s3", - "heltecwslv3": "esp32s3", + "ai-c3": "esp32c3", + "esp32c3_super_mini": "esp32c3", + "esp32c3_base": "esp32", + "hackerboxes-esp32c3-oled": "esp32c3", + "heltec-ht62-esp32c3-sx1262": "esp32c3", + "heltec-hru-3601": "esp32c3", + "m5stack-stamp-c3": "esp32c3", + "esp32c6_base": "esp32", + "m5stack-unitc6l": "esp32c6", + "tlora-c6": "esp32c6", + "esp32s2_base": "esp32", + "nugget-s2-lora": "esp32s2", + "CDEBYTE_EoRa-S3": "esp32s3", + "EBYTE_ESP32-S3": "esp32s3", + "thinknode_m2": "esp32s3", + "thinknode_m5": "esp32s3", + "bpi_picow_esp32_s3": "esp32s3", + "crowpanel-esp32s3-5-epaper": "esp32s3", + "crowpanel-esp32s3-4-epaper": "esp32s3", + "crowpanel-esp32s3-2-epaper": "esp32s3", + "my-esp32s3-diy-eink": "esp32s3", + "my-esp32s3-diy-oled": "esp32s3", + "t-energy-s3_e22": "esp32s3", + "dreamcatcher-2206": "esp32s3", + "crowpanel_base": "crowpanel", + "elecrow-adv-24-28-tft": "crowpanel_small_esp32s3_base", + "elecrow-adv-35-tft": "crowpanel_small_esp32s3_base", + "elecrow-adv1-43-50-70-tft": "crowpanel_large_esp32s3_base", + "ESP32-S3-Pico": "esp32s3", + "esp32s3_base": "esp32", + "hackaday-communicator": "esp32s3", + "heltec_capsule_sensor_v3": "esp32s3", + "heltec_sensor_hub": "esp32s3", + "heltec-v3": "esp32s3", + "heltec_v4_base": "esp32s3", + "heltec-v4": "heltec_v4_base", + "heltec-v4-tft": "heltec_v4_base", + "heltec-vision-master-e213": "esp32s3", + "heltec-vision-master-e213-inkhud": "esp32s3", + "heltec-vision-master-e290": "esp32s3", + "heltec-vision-master-e290-inkhud": "esp32s3", + "heltec-vision-master-t190": "esp32s3", + "heltec-wireless-paper": "esp32s3", + "heltec-wireless-paper-inkhud": "esp32s3", + "heltec-wireless-paper-v1_0": "esp32s3", + "heltec-wireless-tracker": "esp32s3", + "heltec-wireless-tracker-V1-0": "esp32s3", + "heltec-wireless-tracker-v2": "esp32s3", + "heltec-wsl-v3": "esp32s3", "icarus": "esp32s3", - "link32s3v1": "esp32s3", - "m5stackcores3": "esp32s3", - "meshtabbase": "esp32s3", - "meshtab32TNresistive": "meshtabbase", - "meshtab32IPSresistive": "meshtabbase", - "meshtab35IPSresistive": "meshtabbase", - "meshtab35TNresistive": "meshtabbase", - "meshtab32IPScapacitive": "meshtabbase", - "meshtab35IPScapacitive": "meshtabbase", - "meshtab40IPScapacitive": "meshtabbase", - "nibbleesp32": "esp32s3", - "nuggets3lora": "esp32s3", - "picomputers3": "esp32s3", - "picomputers3tft": "picomputers3", + "link32-s3-v1": "esp32s3", + "m5stack-cores3": "esp32s3", + "mesh_tab_base": "esp32s3", + "mesh-tab-3-2-TN-resistive": "mesh_tab_base", + "mesh-tab-3-2-IPS-resistive": "mesh_tab_base", + "mesh-tab-3-5-IPS-resistive": "mesh_tab_base", + "mesh-tab-3-5-TN-resistive": "mesh_tab_base", + "mesh-tab-3-2-IPS-capacitive": "mesh_tab_base", + "mesh-tab-3-5-IPS-capacitive": "mesh_tab_base", + "mesh-tab-4-0-IPS-capacitive": "mesh_tab_base", + "nibble-esp32": "esp32s3", + "nugget-s3-lora": "esp32s3", + "picomputer-s3": "esp32s3", + "picomputer-s3-tft": "picomputer-s3", "rak3312": "esp32s3", - "rakwismeshtapv2tft": "rakwismeshtaps3", - "seeedsensecapindicator": "esp32s3", - "seeedsensecapindicatortft": "seeedsensecapindicator", - "seeedxiaos3": "esp32s3", - "stationg2": "esp32s3", - "tdeck": "esp32s3", - "tdecktft": "tdeck", - "tdeckpro": "esp32s3", - "tethelite": "esp32s3", - "twatchs3": "esp32s3", - "tbeams3core": "esp32s3", - "tlorapager": "esp32s3", - "tlorapagertft": "tlorapager", - "tlorat3s3epaper": "esp32s3", - "tlorat3s3epaperinkhud": "esp32s3", - "tlorat3s3v1": "esp32s3", + "rak_wismesh_tap_v2-tft": "rak_wismeshtap_s3", + "seeed-sensecap-indicator": "esp32s3", + "seeed-sensecap-indicator-tft": "seeed-sensecap-indicator", + "seeed-xiao-s3": "esp32s3", + "station-g2": "esp32s3", + "t-deck": "esp32s3", + "t-deck-tft": "t-deck", + "t-deck-pro": "esp32s3", + "t-eth-elite": "esp32s3", + "t-watch-s3": "esp32s3", + "tbeam-s3-core": "esp32s3", + "tlora-pager": "esp32s3", + "tlora-pager-tft": "tlora-pager", + "tlora-t3s3-epaper": "esp32s3", + "tlora-t3s3-epaper-inkhud": "esp32s3", + "tlora-t3s3-v1": "esp32s3", "tracksenger": "esp32s3", - "tracksengerlcd": "esp32s3", - "tracksengeroled": "esp32s3", + "tracksenger-lcd": "esp32s3", + "tracksenger-oled": "esp32s3", "unphone": "esp32s3", - "unphonetft": "unphone", + "unphone-tft": "unphone", "coverage": "native", "buildroot": "portduino", - "pca10059diyeink": "nrf52840", - "thinknodem1": "nrf52840", - "thinknodem1inkhud": "nrf52840", - "thinknodem3": "nrf52840", - "thinknodem6": "nrf52840", - "ME25LS014Y10TD": "nrf52840", - "ME25LS014Y10TDeink": "nrf52840", + "pca10059_diy_eink": "nrf52840", + "thinknode_m1": "nrf52840", + "thinknode_m1-inkhud": "nrf52840", + "thinknode_m3": "nrf52840", + "thinknode_m6": "nrf52840", + "ME25LS01-4Y10TD": "nrf52840", + "ME25LS01-4Y10TD_e-ink": "nrf52840", "ms24sf1": "nrf52840", - "makerpythonnrf52840sx1280eink": "nrf52840", - "makerpythonnrf52840sx1280oled": "nrf52840", - "TWCmeshv4": "nrf52840", + "makerpython_nrf52840_sx1280_eink": "nrf52840", + "makerpython_nrf52840_sx1280_oled": "nrf52840", + "TWC_mesh_v4": "nrf52840", "canaryone": "nrf52840", "WashTastic": "nrf52840", - "nrf52promicrodiytcxo": "nrf52840", - "nrf52promicrodiyinkhud": "nrf52840", - "seeedxiaonrf52840wiosx1262": "nrf52840", - "seeedxiaonrf52840e22900m30s": "seeedxiaonrf52840kit", - "seeedxiaonrf52840e22900m33s": "seeedxiaonrf52840kit", - "xiaoble": "seeedxiaonrf52840kit", - "featherdiy": "nrf52840", - "gat562meshtrialtracker": "nrf52840", - "heltecmeshnodet114": "nrf52840", - "heltecmeshnodet114inkhud": "nrf52840", - "heltecmeshpocket5000": "nrf52840", - "heltecmeshpocket5000inkhud": "nrf52840", - "heltecmeshpocket10000": "nrf52840", - "heltecmeshpocket10000inkhud": "nrf52840", - "heltecmeshsolarbase": "nrf52840", - "heltecmeshsolar": "heltecmeshsolarbase", - "heltecmeshsolareink": "heltecmeshsolarbase", - "heltecmeshsolarinkhud": "heltecmeshsolarbase", - "heltecmeshsolaroled": "heltecmeshsolarbase", - "heltecmeshsolartft": "heltecmeshsolarbase", + "nrf52_promicro_diy_tcxo": "nrf52840", + "nrf52_promicro_diy-inkhud": "nrf52840", + "seeed-xiao-nrf52840-wio-sx1262": "nrf52840", + "seeed_xiao_nrf52840_e22_900m30s": "seeed_xiao_nrf52840_kit", + "seeed_xiao_nrf52840_e22_900m33s": "seeed_xiao_nrf52840_kit", + "xiao_ble": "seeed_xiao_nrf52840_kit", + "feather_diy": "nrf52840", + "gat562_mesh_trial_tracker": "nrf52840", + "heltec-mesh-node-t114": "nrf52840", + "heltec-mesh-node-t114-inkhud": "nrf52840", + "heltec-mesh-pocket-5000": "nrf52840", + "heltec-mesh-pocket-5000-inkhud": "nrf52840", + "heltec-mesh-pocket-10000": "nrf52840", + "heltec-mesh-pocket-10000-inkhud": "nrf52840", + "heltec_mesh_solar_base": "nrf52840", + "heltec-mesh-solar": "heltec_mesh_solar_base", + "heltec-mesh-solar-eink": "heltec_mesh_solar_base", + "heltec-mesh-solar-inkhud": "heltec_mesh_solar_base", + "heltec-mesh-solar-oled": "heltec_mesh_solar_base", + "heltec-mesh-solar-tft": "heltec_mesh_solar_base", "meshlink": "nrf52840", - "meshlinkeink": "nrf52840", + "meshlink_eink": "nrf52840", "meshtiny": "nrf52840", - "monteopshw1": "nrf52840", - "muzibase": "nrf52840", - "nanog2ultra": "nrf52840", - "nrf52832base": "nrf52", - "nrf52840base": "nrf52", - "r1neo": "nrf52840", + "monteops_hw1": "nrf52840", + "muzi-base": "nrf52840", + "nano-g2-ultra": "nrf52840", + "nrf52832_base": "nrf52", + "nrf52840_base": "nrf52", + "r1-neo": "nrf52840", "rak2560": "nrf52840", - "rak34011watt": "nrf52840", + "rak3401-1watt": "nrf52840", "rak4631": "nrf52840", - "rak4631dbg": "rak4631", - "rak4631eink": "nrf52840", - "rak4631einkonrxtx": "nrf52840", - "rak4631ethgw": "nrf52840", - "rak4631ethgwdbg": "rak4631", - "rak4631nomadstarmeteorpro": "nrf52840", - "rak4631nomadstarmeteorprodbg": "rak4631nomadstarmeteorpro", - "rakwismeshtag": "nrf52840", - "rakwismeshtap": "nrf52840", - "seeedsolarnode": "nrf52840", - "seeedwiotrackerL1": "nrf52840", - "seeedwiotrackerL1eink": "nrf52840", - "seeedwiotrackerL1einkinkhud": "nrf52840", - "seeedxiaonrf52840kit": "nrf52840", - "seeedxiaonrf52840kiti2c": "seeedxiaonrf52840kit", - "techo": "nrf52840", - "techoinkhud": "nrf52840", - "techolite": "nrf52840", - "trackert1000e": "nrf52840", - "wiosdkwm1110": "nrf52840", - "wiot1000s": "nrf52840", - "wiotrackerwm1110": "nrf52840", - "challenger2040lora": "rp2040", + "rak4631_dbg": "rak4631", + "rak4631_eink": "nrf52840", + "rak4631_eink_onrxtx": "nrf52840", + "rak4631_eth_gw": "nrf52840", + "rak4631_eth_gw_dbg": "rak4631", + "rak4631_nomadstar_meteor_pro": "nrf52840", + "rak4631_nomadstar_meteor_pro_dbg": "rak4631_nomadstar_meteor_pro", + "rak_wismeshtag": "nrf52840", + "rak_wismeshtap": "nrf52840", + "seeed_solar_node": "nrf52840", + "seeed_wio_tracker_L1": "nrf52840", + "seeed_wio_tracker_L1_eink": "nrf52840", + "seeed_wio_tracker_L1_eink-inkhud": "nrf52840", + "seeed_xiao_nrf52840_kit": "nrf52840", + "seeed_xiao_nrf52840_kit_i2c": "seeed_xiao_nrf52840_kit", + "t-echo": "nrf52840", + "t-echo-inkhud": "nrf52840", + "t-echo-lite": "nrf52840", + "tracker-t1000-e": "nrf52840", + "wio-sdk-wm1110": "nrf52840", + "wio-t1000-s": "nrf52840", + "wio-tracker-wm1110": "nrf52840", + "challenger_2040_lora": "rp2040", "catsniffer": "rp2040", - "featherrp2040rfm95": "rp2040", - "nibblerp2040": "rp2040", + "feather_rp2040_rfm95": "rp2040", + "nibble-rp2040": "rp2040", "rak11310": "rp2040", - "rp2040lora": "rp2040", + "rp2040-lora": "rp2040", "pico": "rp2040", - "picoslowclock": "rp2040", + "pico_slowclock": "rp2040", "picow": "rp2040", - "senselorarp2040": "rp2040", + "senselora_rp2040": "rp2040", "pico2": "rp2350", "pico2w": "rp2350", - "CDEBYTEE77MBL": "stm32", + "CDEBYTE_E77-MBL": "stm32", "rak3172": "stm32", - "wioe5": "stm32", + "wio-e5": "stm32", "esp32c3": "esp32", "esp32c6": "esp32", "esp32s2": "esp32", @@ -217,4 +217,4 @@ "rp2350": null, "stm32": null, "portduino": null -} +} \ No newline at end of file diff --git a/constants/targets.ts b/constants/targets.ts index 47c37c3..f6d994e 100644 --- a/constants/targets.ts +++ b/constants/targets.ts @@ -1,4 +1,5 @@ -import hardwareList from "@/vendor/web-flasher/public/data/hardware-list.json" +import architectureHierarchy from "@/constants/architecture-hierarchy.json" +import vendorsData from "@/constants/vendors.json" export interface TargetMetadata { name: string @@ -6,17 +7,43 @@ export interface TargetMetadata { architecture?: string } +/** + * Trace a target back to its base architecture + */ +function getBaseArchitecture(target: string): string | null { + const parentMap = architectureHierarchy as Record + const visited = new Set() + let current: string | null = target + + while (current && !visited.has(current)) { + visited.add(current) + if (!current) break + const parent: string | null | undefined = parentMap[current] + + if (parent === null) { + return current + } + + if (parent === undefined) { + return current + } + + current = parent + } + + return current || target +} + export const TARGETS: Record = {} -// Sort by display name -const sortedHardware = [...hardwareList].sort((a, b) => (a.displayName || "").localeCompare(b.displayName || "")) - -sortedHardware.forEach(hw => { - if (hw.platformioTarget) { - TARGETS[hw.platformioTarget] = { - name: hw.displayName || hw.platformioTarget, - category: hw.tags?.[0] || "Other", - architecture: hw.architecture, +// Build TARGETS from vendors.json and architecture-hierarchy.json +for (const [vendor, models] of Object.entries(vendorsData)) { + for (const [modelName, target] of Object.entries(models)) { + const architecture = getBaseArchitecture(target) + TARGETS[target] = { + name: modelName, + category: vendor, + architecture: architecture || undefined, } } -}) +} diff --git a/constants/vendors.json b/constants/vendors.json new file mode 100644 index 0000000..78f4b73 --- /dev/null +++ b/constants/vendors.json @@ -0,0 +1,244 @@ +{ + "B&Q": { + "Nano G1": "nano-g1", + "Nano G1 Explorer": "nano-g1-explorer", + "Nano G2 Ultra": "nano-g2-ultra", + "Station G1": "station-g1", + "Station G2": "station-g2" + }, + "BetaFPV": { + "2400TX Micro": "betafpv_2400_tx_micro", + "900TX Nano": "betafpv_900_tx_nano" + }, + "Canary": { + "One": "canaryone" + }, + "CDEByte": { + "EoRa S3": "CDEBYTE_EoRa-S3", + "E77MBL": "CDEBYTE_E77-MBL" + }, + "DIY": { + "DR-DEV": "meshtastic-dr-dev", + "Hydra": "hydra", + "V1": "meshtastic-diy-v1", + "V1.1": "meshtastic-diy-v1_1", + "NRF52 Pro-micro DIY": "nrf52_promicro_diy_tcxo", + "NRF52 Pro-micro DIY InkHUD": "nrf52_promicro_diy-inkhud", + "PCA10059 DIY E-Ink": "pca10059_diy_eink" + }, + "EByte": { + "ESP32-S3": "EBYTE_ESP32-S3" + }, + "Elecrow": { + "Crowpanel Adv 2.4/2.8 TFT": "elecrow-adv-24-28-tft", + "Crowpanel Adv 3.5 TFT": "elecrow-adv-35-tft", + "Crowpanel Adv 4.3/5.0/7.0 TFT": "elecrow-adv1-43-50-70-tft", + "ThinkNode M1": "thinknode_m1", + "ThinkNode M2": "thinknode_m2", + "ThinkNode M3": "thinknode_m3", + "ThinkNode M5": "thinknode_m5", + "ThinkNode M6": "thinknode_m6" + }, + "Heltec": { + "V1": "heltec-v1", + "V2.0": "heltec-v2_0", + "V2.1": "heltec-v2_1", + "V3": "heltec-v3", + "V4": "heltec-v4", + "V4 TFT": "heltec-v4-tft", + "HT62": "heltec-ht62-esp32c3-sx1262", + "RU3601": "heltec-hru-3601", + "Wireless Bridge": "heltec-wireless-bridge", + "Wireless Stick Lite V2.1": "heltec-wsl-v2_1", + "Wireless Stick Lite V3": "heltec-wsl-v3", + "Wireless Paper": "heltec-wireless-paper", + "Wireless Paper InkHUD": "heltec-wireless-paper-inkhud", + "Wireless Paper V1.0": "heltec-wireless-paper-v1_0", + "Wireless Tracker": "heltec-wireless-tracker", + "Wireless Tracker V1.0": "heltec-wireless-tracker-V1-0", + "Wireless Tracker V2": "heltec-wireless-tracker-v2", + "Vision Master E213": "heltec-vision-master-e213", + "Vision Master E213 InkHUD": "heltec-vision-master-e213-inkhud", + "Vision Master E290": "heltec-vision-master-e290", + "Vision Master E290 InkHUD": "heltec-vision-master-e290-inkhud", + "Vision Master T190": "heltec-vision-master-t190", + "Capsule Sensor V3": "heltec_capsule_sensor_v3", + "Sensor Hub": "heltec_sensor_hub", + "Mesh Node T114": "heltec-mesh-node-t114", + "Mesh Node T114 InkHUD": "heltec-mesh-node-t114-inkhud", + "MeshPocket 5000": "heltec-mesh-pocket-5000", + "MeshPocket 5000 InkHUD": "heltec-mesh-pocket-5000-inkhud", + "MeshPocket 10000": "heltec-mesh-pocket-10000", + "MeshPocket 10000 InkHUD": "heltec-mesh-pocket-10000-inkhud", + "MeshSolar": "heltec-mesh-solar", + "MeshSolar E-Ink": "heltec-mesh-solar-eink", + "MeshSolar InkHUD": "heltec-mesh-solar-inkhud", + "MeshSolar OLED": "heltec-mesh-solar-oled", + "MeshSolar TFT": "heltec-mesh-solar-tft" + }, + "HackerBoxes": { + "ESP32 IO": "hackerboxes-esp32-io", + "ESP32-C3 OLED": "hackerboxes-esp32c3-oled" + }, + "LilyGo": { + "T-Beam": "tbeam", + "T-Beam Display Shield": "tbeam-displayshield", + "T-Beam V0.7": "tbeam0_7", + "T-Beam S3 Core": "tbeam-s3-core", + "T-Deck": "t-deck", + "T-Deck TFT": "t-deck-tft", + "T-Deck Pro": "t-deck-pro", + "T-Echo": "t-echo", + "T-Echo InkHUD": "t-echo-inkhud", + "T-Echo Lite": "t-echo-lite", + "T-LoRa V1": "tlora-v1", + "T-LoRa V1.3": "tlora_v1_3", + "T-LoRa V2": "tlora-v2", + "T-LoRa V2.1-1.6": "tlora-v2-1-1_6", + "T-LoRa V2.1-1.6 TCXO": "tlora-v2-1-1_6-tcxo", + "T-LoRa V2.1-1.8": "tlora-v2-1-1_8", + "T-LoRa V3.3.0 TCXO": "tlora-v3-3-0-tcxo", + "T-LoRa C6": "tlora-c6", + "T-LoRa Pager": "tlora-pager", + "T-LoRa Pager TFT": "tlora-pager-tft", + "T-LoRa T3-S3": "tlora-t3s3-v1", + "T-LoRa T3-S3 E-Paper": "tlora-t3s3-epaper", + "T-LoRa T3-S3 E-Paper InkHUD": "tlora-t3s3-epaper-inkhud", + "T-Watch S3": "t-watch-s3", + "Sugar Cube": "sugarcube" + }, + "M5Stack": { + "Core": "m5stack-core", + "Core Ink": "m5stack-coreink", + "Core S3": "m5stack-cores3", + "Stamp C3": "m5stack-stamp-c3", + "Unit C6L": "m5stack-unitc6l" + }, + "MakerPython": { + "NRF52840 SX1280 E-Ink": "makerpython_nrf52840_sx1280_eink", + "NRF52840 SX1280 OLED": "makerpython_nrf52840_sx1280_oled" + }, + "muzi": { + "R1 Neo": "r1-neo" + }, + "NomadStar": { + "Meteor Pro": "rak4631_nomadstar_meteor_pro", + "Meteor Pro Debug": "rak4631_nomadstar_meteor_pro_dbg" + }, + "RAK": { + "WisBlock 11200": "rak11200", + "WisBlock 11310": "rak11310", + "WisBlock 4631": "rak4631", + "WisBlock 4631 Debug": "rak4631_dbg", + "WisBlock 4631 E-Ink": "rak4631_eink", + "WisBlock 4631 E-Ink on RX/TX": "rak4631_eink_onrxtx", + "WisBlock 4631 ETH Gateway": "rak4631_eth_gw", + "WisBlock 4631 ETH Gateway Debug": "rak4631_eth_gw_dbg", + "WisBlock 3312": "rak3312", + "WisBlock 3172": "rak3172", + "WisBlock 2560": "rak2560", + "WisBlock 3401 1Watt": "rak3401-1watt", + "WisMesh Tag": "rak_wismeshtag", + "WisMesh Tap": "rak_wismeshtap", + "WisMesh Tap V2 TFT": "rak_wismesh_tap_v2-tft" + }, + "RadioMaster": { + "900 Bandit": "radiomaster_900_bandit", + "900 Bandit Micro": "radiomaster_900_bandit_micro", + "900 Bandit Nano": "radiomaster_900_bandit_nano" + }, + "RPi": { + "Pico": "pico", + "Pico Slow Clock": "pico_slowclock", + "Pico W": "picow", + "Pico 2": "pico2", + "Pico 2W": "pico2w" + }, + "Seeed": { + "Xiao ESP32-S3": "seeed-xiao-s3", + "Xiao NRF52840 Kit": "seeed_xiao_nrf52840_kit", + "Xiao NRF52840 Kit I2C": "seeed_xiao_nrf52840_kit_i2c", + "Xiao NRF52840 WIO SX1262": "seeed-xiao-nrf52840-wio-sx1262", + "Xiao NRF52840 E22900M30S": "seeed_xiao_nrf52840_e22_900m30s", + "Xiao NRF52840 E22900M33S": "seeed_xiao_nrf52840_e22_900m33s", + "Xiao BLE": "xiao_ble", + "Wio Tracker L1": "seeed_wio_tracker_L1", + "Wio Tracker L1 E-Ink": "seeed_wio_tracker_L1_eink", + "Wio Tracker L1 E-Ink InkHUD": "seeed_wio_tracker_L1_eink-inkhud", + "Wio Tracker WM1110": "wio-tracker-wm1110", + "Wio SDK WM1110": "wio-sdk-wm1110", + "Wio T1000S": "wio-t1000-s", + "SenseCAP Indicator": "seeed-sensecap-indicator", + "SenseCAP Indicator TFT": "seeed-sensecap-indicator-tft", + "Solar Node": "seeed_solar_node" + }, + "Waveshare": { + "RP2040 LoRa": "rp2040-lora" + }, + "Other": { + "Chatter2": "chatter2", + "9M2 IBRA PRS LoRa Tracker": "9m2ibr_aprs_lora_tracker", + "AIC3": "ai-c3", + "ESP32-C3": "esp32c3", + "ESP32-C3 Super Mini": "esp32c3_super_mini", + "ESP32-C6": "esp32c6", + "ESP32-S2": "esp32s2", + "ESP32-S3": "esp32s3", + "ESP32-S3 Pico": "ESP32-S3-Pico", + "Crowpanel ESP32-S3 2 E-Paper": "crowpanel-esp32s3-2-epaper", + "Crowpanel ESP32-S3 4 E-Paper": "crowpanel-esp32s3-4-epaper", + "Crowpanel ESP32-S3 5 E-Paper": "crowpanel-esp32s3-5-epaper", + "BPi Pico W ESP32-S3": "bpi_picow_esp32_s3", + "My ESP32-S3 DIY E-Ink": "my-esp32s3-diy-eink", + "My ESP32-S3 DIY OLED": "my-esp32s3-diy-oled", + "T-Energy S3 E22": "t-energy-s3_e22", + "Dreamcatcher 2206": "dreamcatcher-2206", + "Hackaday Communicator": "hackaday-communicator", + "Icarus": "icarus", + "Link32S3 V1": "link32-s3-v1", + "MeshTab 32 TN Resistive": "mesh-tab-3-2-TN-resistive", + "MeshTab 32 IPS Resistive": "mesh-tab-3-2-IPS-resistive", + "MeshTab 35 IPS Resistive": "mesh-tab-3-5-IPS-resistive", + "MeshTab 35 TN Resistive": "mesh-tab-3-5-TN-resistive", + "MeshTab 32 IPS Capacitive": "mesh-tab-3-2-IPS-capacitive", + "MeshTab 35 IPS Capacitive": "mesh-tab-3-5-IPS-capacitive", + "MeshTab 40 IPS Capacitive": "mesh-tab-4-0-IPS-capacitive", + "Nibble ESP32": "nibble-esp32", + "Nugget S2 LoRa": "nugget-s2-lora", + "Nugget S3 LoRa": "nugget-s3-lora", + "Pi Computer S3": "picomputer-s3", + "Pi Computer S3 TFT": "picomputer-s3-tft", + "T-Echo Lite": "t-eth-elite", + "Tracksenger": "tracksenger", + "Tracksenger LCD": "tracksenger-lcd", + "Tracksenger OLED": "tracksenger-oled", + "unPhone": "unphone", + "unPhone TFT": "unphone-tft", + "NRF52832": "nrf52832", + "NRF52840": "nrf52840", + "ThinkNode M1 InkHUD": "thinknode_m1-inkhud", + "ME25LS014Y10TD": "ME25LS01-4Y10TD", + "ME25LS014Y10TD E-Ink": "ME25LS01-4Y10TD_e-ink", + "MS24SF1": "ms24sf1", + "TWC Mesh V4": "TWC_mesh_v4", + "WashTastic": "WashTastic", + "Feather DIY": "feather_diy", + "Feather RP2040 RFM95": "feather_rp2040_rfm95", + "GAT562 Mesh Trial Tracker": "gat562_mesh_trial_tracker", + "MeshLink": "meshlink", + "MeshLink E-Ink": "meshlink_eink", + "MeshTiny": "meshtiny", + "MonteOps HW1": "monteops_hw1", + "R1 Neo": "r1-neo", + "Tracker T1000E": "tracker-t1000-e", + "Tracker D": "trackerd", + "WiPhone": "wiphone", + "Challenger 2040 LoRa": "challenger_2040_lora", + "Cat Sniffer": "catsniffer", + "Nibbler RP2040": "nibble-rp2040", + "SenseLoRa RP2040": "senselora_rp2040", + "Wio E5": "wio-e5", + "Coverage": "coverage", + "Buildroot": "buildroot" + } +} diff --git a/lib/utils.ts b/lib/utils.ts index 57a1ea8..0f17e98 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -127,30 +127,19 @@ export function isRequiredByOther( return false } -/** - * Normalize architecture name (remove hyphens and underscores to match PlatformIO format) - * PlatformIO uses "esp32s3", "nrf52840" (no hyphens, no underscores) - * Hardware list uses "esp32-s3" (with hyphens) - * Some sources might use "esp32_s3" (with underscores) - */ -function normalizeArchitecture(arch: string): string { - return arch.replace(/[-_]/g, "") -} - /** * Trace a target/variant/architecture back to its base architecture * Follows the parent chain until it reaches a base architecture (null parent) */ export function getBaseArchitecture(name: string): string | null { - const normalized = normalizeArchitecture(name) const parentMap = PARENT_MAP as Record - const visited = new Set() - let current = normalized + let current: string | null = name while (current && !visited.has(current)) { visited.add(current) - const parent = parentMap[current] + if (!current) break + const parent: string | null | undefined = parentMap[current] // If parent is null, we've reached a base architecture if (parent === null) { @@ -162,11 +151,11 @@ export function getBaseArchitecture(name: string): string | null { return current } - current = normalizeArchitecture(parent) + current = parent } // Circular reference or unknown, return the last known - return current || normalized + return current || name } /** @@ -174,17 +163,16 @@ export function getBaseArchitecture(name: string): string | null { * (including itself and all parent architectures up to base) */ export function getCompatibleArchitectures(arch: string): string[] { - const normalized = normalizeArchitecture(arch) const parentMap = PARENT_MAP as Record - - const compatible = [normalized] + const compatible = [arch] const visited = new Set() - let current = normalized + let current: string | null = arch // Follow parent chain up to base architecture while (current && !visited.has(current)) { visited.add(current) - const parent = parentMap[current] + if (!current) break + const parent: string | null | undefined = parentMap[current] if (parent === null) { // Reached base architecture @@ -196,12 +184,11 @@ export function getCompatibleArchitectures(arch: string): string[] { break } - const normalizedParent = normalizeArchitecture(parent) - if (!compatible.includes(normalizedParent)) { - compatible.push(normalizedParent) + if (!compatible.includes(parent)) { + compatible.push(parent) } - current = normalizedParent + current = parent } return compatible @@ -227,18 +214,16 @@ export function isPluginCompatibleWithTarget( const parentMap = PARENT_MAP as Record - // Normalize target name first (all keys in parentMap are normalized) - const normalizedTarget = normalizeArchitecture(targetName) - // Get all compatible names for the target (target itself + all parents up to base architecture) - const compatibleNames = new Set([normalizedTarget]) + const compatibleNames = new Set([targetName]) const visited = new Set() - let current = normalizedTarget + let current: string | null = targetName - // Follow parent chain (all keys and values in parentMap are already normalized) + // Follow parent chain while (current && !visited.has(current)) { visited.add(current) - const parent = parentMap[current] + if (!current) break + const parent: string | null | undefined = parentMap[current] if (parent === null) { // Reached base architecture @@ -251,30 +236,21 @@ export function isPluginCompatibleWithTarget( break } - // Parent is already normalized (from JSON) compatibleNames.add(parent) current = parent } // Check excludes first - if target matches any exclude, it's incompatible - // compatibleNames are already normalized, normalize excludes for comparison if (pluginExcludes && pluginExcludes.length > 0) { - const isExcluded = pluginExcludes.some(exclude => { - const normalizedExclude = normalizeArchitecture(exclude) - return compatibleNames.has(normalizedExclude) - }) + const isExcluded = pluginExcludes.some(exclude => compatibleNames.has(exclude)) if (isExcluded) { return false } } // If includes are specified, target must match at least one include - // compatibleNames are already normalized, normalize includes for comparison if (pluginIncludes && pluginIncludes.length > 0) { - return pluginIncludes.some(include => { - const normalizedInclude = normalizeArchitecture(include) - return compatibleNames.has(normalizedInclude) - }) + return pluginIncludes.some(include => compatibleNames.has(include)) } // If no includes/excludes specified, assume compatible with all (backward compatible) @@ -301,34 +277,30 @@ export function isPluginCompatibleWithArchitecture( export function getTargetsCompatibleWithIncludes(includes: string[]): Set { const parentMap = PARENT_MAP as Record const compatibleTargets = new Set() - - // Normalize includes - const normalizedIncludes = new Set(includes.map(include => normalizeArchitecture(include))) + const includesSet = new Set(includes) // For each target in the parent map, check if it or any of its ancestors match the includes for (const target of Object.keys(parentMap)) { - const normalizedTarget = normalizeArchitecture(target) const visited = new Set() - let current: string | null = normalizedTarget + let current: string | null = target // Trace up the parent chain while (current && !visited.has(current)) { visited.add(current) + if (!current) break // Check if current matches any of the includes - if (normalizedIncludes.has(current)) { - // Add both the normalized version and the original (for matching against TARGETS) - compatibleTargets.add(normalizedTarget) + if (includesSet.has(current)) { compatibleTargets.add(target) break } // Move to parent - const parentValue = parentMap[current] - if (parentValue === null || parentValue === undefined) { + const parent: string | null | undefined = parentMap[current] + if (parent === null || parent === undefined) { break } - current = normalizeArchitecture(parentValue) + current = parent } } diff --git a/scripts/generate-architecture-hierarchy.js b/scripts/generate-architecture-hierarchy.js index 5b1510d..4ed6d3a 100644 --- a/scripts/generate-architecture-hierarchy.js +++ b/scripts/generate-architecture-hierarchy.js @@ -9,14 +9,6 @@ const FIRMWARE_DIR = path.resolve(__dirname, "../vendor/firmware") const VARIANTS_DIR = path.join(FIRMWARE_DIR, "variants") const OUTPUT_FILE = path.resolve(__dirname, "../constants/architecture-hierarchy.json") -/** - * Normalize architecture/target name (remove hyphens and underscores) - * This ensures consistent format matching PlatformIO architecture names - */ -function normalizeName(name) { - return name.replace(/[-_]/g, "") -} - /** * Parse PlatformIO ini file to extract sections and their properties */ @@ -342,15 +334,8 @@ function buildParentMapping() { delete resolvedParentMap[key] } - // Normalize all keys and values (strip hyphens and underscores) - const normalizedMap = {} - for (const [key, value] of Object.entries(resolvedParentMap)) { - const normalizedKey = normalizeName(key) - const normalizedValue = value !== null ? normalizeName(value) : null - normalizedMap[normalizedKey] = normalizedValue - } - - return normalizedMap + // Return map with actual PlatformIO environment names (no normalization) + return resolvedParentMap } /**